Как запретить Android делать снимок экрана, когда мое приложение переходит в фоновый режим?

146

Приложение, которое я сейчас создаю, требует, чтобы приложение не позволяло ОС делать снимок экрана приложения, когда оно перемещается в фоновый режим из соображений безопасности. Таким образом, он не сможет увидеть последний активный экран при переключении между приложениями.

Я планирую поместить эту функциональность в метод onPause класса приложения, но сначала мне нужно выяснить, как я могу добиться этой функциональности.

Так есть ли кто-нибудь, кто знает, как это исправить?

StingRay5
источник

Ответы:

264

Попробуй FLAG_SECURE:

public class FlagSecureTestActivity extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
                         WindowManager.LayoutParams.FLAG_SECURE);

    setContentView(R.layout.main);
  }
}

Это определенно защищает от ручных снимков экрана и автоматических снимков экрана из истории недавних задач ICS. Он также защищает от записи экрана (например, приложений, использующих API проекции мультимедиа).

ОБНОВЛЕНИЕ : это также защищает от Now On Tap или других помощников на Android 6.0; они не получат доступ к деталям виджетов и контейнеров в вашем пользовательском интерфейсе, если пользователь вызовет помощника.

ОБНОВЛЕНИЕ № 2 : однако, не все в деятельности будут защищены. Любые всплывающие окна - Dialog, Spinner, AutoCompleteTextView, действие Переполнение бар и т.д. - будет небезопасно. Вы можете решить Dialogпроблему, вызвав getWindow()ее и установив FLAG_SECURE. Остальное ... становится сложнее. Смотрите этот блог для получения дополнительной информации.

CommonsWare
источник
6
@ Дэни: На самом деле, это все, что связано с вопросом. Я только что проверил его на Nexus S (4.0.3), и он работает, как и ожидалось - скриншот недавних задач подавлен. Вы по-прежнему видите название и значок приложения, но снимок экрана черный. Вы можете попробовать это на оборудовании ICS.
CommonsWare
2
@ StingRay5: FLAG_SECUREсуществует с самого начала - до недавнего времени он имел ограниченное значение.
CommonsWare
1
Интересно отметить, что есть метод с именем onCreateThumbnail в жизненном цикле действия, но он никогда не используется.
Сниколас
2
@PankajKumar: Если «код для создания снимка экрана», который вы написали, является классическим трюком «захват фреймбуфера как root», FLAG_SECUREон не защитится от этого, поскольку он слишком низкоуровневый. Точно так же, если вы взяли свою собственную иерархию виджетов и Bitmapобратили ее к -backed Canvas, FLAG_SECUREвероятно, не защититесь от этого, так как вы делаете свои собственные скриншоты своих собственных виджетов и, следовательно, по-видимому, хотели иметь «безопасные» там. FLAG_SECUREдля системных скриншотов, таких как миниатюры недавних задач.
CommonsWare
2
Замечательный и простой ответ! Мне интересно, почему такие приложения, как Snapchat , не используют это, чтобы не сделать снимок экрана с отправленными снимками.
Шобхит Пури
78

Будьте осторожны с использованием WindowManager.LayoutParams.FLAG_SECURE, на некоторых устройствах (проверено на Samsung Galaxy ACE, например GT-S5830) это сделает представление зашифрованным. Похоже, конкретная ошибка Samsung. Я рекомендую следующее:

if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}

Вот как выглядит скремблированный экран:

Скремблированное изображение на экране

Это работает должным образом на телефонах ICS Samsung, поэтому я предполагаю, что проблема изолирована от устройств Gingerbread (или более старых).

gardarh
источник
8
Вы совершенно правы, мы столкнулись с этой проблемой, и она, безусловно, была необходима для проверки уровня API. На самом деле забыл опубликовать это, так что спасибо, что поднял его снова. :)
StingRay5
Это также происходит на Samsung Gio (Gingerbread), но на Froyo все нормально - так что это происходит только на 2.3
пиксель
Мы заметили и эту проблему. Вы можете проверить это в эмуляторе на устройствах Gingerbread.
Twaddington
Я также могу подтвердить, что эта проблема появляется на устройствах Samsung Gingerbread.
Эрнир Эрлингссон
7
Даже в более новых версиях Android FLAG_SECURE может быть проблематичным: в Android 4.3 FLAG_SECURE вызывает проблемы с анимацией при анимации вращения экрана, см. Code.google.com/p/android/issues/detail?id=58632 - это было исправлено в Android 4.4
Оливер
13

Решение, предоставленное CommonsWare, продолжает действовать и в Lollipop.

Просто обратите внимание: если вы хотите, чтобы по-прежнему не отображались снимки в недавнем списке для всего приложения, ВСЕ реализованные действия должны указывать в onCreate()методе флаг getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); передsetContentView();

В противном случае снимок в последнем списке покажет первое действие без флага, если пользователь прошел через него.

Davideas
источник
1
В моем приложении есть функция установки / очистки FLAG_SECURE в зависимости от предпочтений пользователя. Он работал нормально, пока KITKAT и черный экран не видны в переключателе задач. В Lollipop, Обзор отображает последний снимок моего приложения, время, когда FLAG_SECURE не был установлен (очищен).
r.bhardwaj
@ r.bhardwaj Я думаю, что в этом случае мы не сможем сделать так много, но вы можете посоветовать пользователю, что для изменения необходимо перезапустить приложение, чтобы оно полностью заработало ;-) и все готово.
Давидеас
1
Кто-нибудь нашел способ раздуть пользовательский вид перед тем, как сделать снимок, чтобы это был не просто черный экран? Я пытался раздувать представление о оконном менеджере в onPause, но кажется, что к тому времени уже слишком поздно.
user1064249
Привет @ user1064249 Вы нашли какое-нибудь решение? Я хочу надуть Launcher View до того, как ОС
сделает
1

Вот решение для того, чтобы скрыть содержимое приложения, закрыв его заставкой, когда приложение помещается в фоновый режим. Это не использование техники FLAG_SECURE, я просто переопределяю методы onPause и onResume экранов и изменяю представление, чтобы оно отображало то, что покрывает все сзади.

https://stackoverflow.com/a/52976001/6686912

Д. Мол
источник
0
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
            WindowManager.LayoutParams.FLAG_SECURE);

это сработало для меня, оно не позволяет делать снимок экрана, а также любое встроенное или стороннее приложение для записи с экрана записи.

Суровый Барнвал
источник
0

Это работа для меня после добавления этих строк в onCreate перед setContentView каждого действия.

getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,     
WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.activity_notification);
Арун Праджапати
источник