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

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

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

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


person StingRay5    schedule 22.03.2012    source источник


Ответы (7)


Попробуйте 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. Остальное... становится сложнее. Дополнительную информацию см. в этой записи блога.

person CommonsWare    schedule 22.03.2012
comment
@Dany's: На самом деле, это имеет прямое отношение к вопросу. Я только что протестировал его на Nexus S (4.0.3), и он работает так, как ожидалось — скриншот недавних задач скрыт. Вы по-прежнему видите название и значок приложения, но скриншот черный. Вы можете попробовать его на оборудовании ICS. - person CommonsWare; 22.03.2012
comment
Спасибо, посмотрю, есть идеи, будет ли это работать с пакетом обратной совместимости? - person StingRay5; 22.03.2012
comment
@ StingRay5: FLAG_SECURE существовал с самого начала - до недавнего времени он имел ограниченное значение. - person CommonsWare; 22.03.2012
comment
Интересно отметить, что в жизненном цикле активности есть метод onCreateThumbnail, но он никогда не используется. - person Snicolas; 08.08.2012
comment
@CommonsWare Как я могу проверить, установлен ли LayoutParams.FLAG_SECURE или нет. На самом деле я установил LayoutParams.FLAG_SECURE, чтобы ограничить захват экрана, и я написал код, чтобы сделать снимок экрана, и я могу сделать снимок экрана. Скажите, пожалуйста, как я могу это проверить? - person Pankaj Kumar; 17.06.2013
comment
@PankajKumar: Если код для создания снимка экрана, который вы написали, представляет собой классический захват кадрового буфера в качестве корневого трюка, FLAG_SECURE не защитит от этого, так как это слишком низкоуровневый. Точно так же, если вы взяли свою собственную иерархию виджетов и нарисовали ее на Canvas с поддержкой Bitmap, FLAG_SECURE, вероятно, не защитит от этого, поскольку вы делаете собственные снимки экрана своих собственных виджетов и, следовательно, предположительно хотели Безопасные там. FLAG_SECURE предназначен для скриншотов системы, таких как эскизы недавних задач. - person CommonsWare; 17.06.2013
comment
В порядке. Я понял. Есть ли способ, где я могу проверить, установлен ли FLAG_SECURE или нет? - person Pankaj Kumar; 17.06.2013
comment
@PankajKumar: Для вашего собственного окна вы должны знать, установлено ли FLAG_SECURE или нет, поскольку вы сами его устанавливаете. Если вы пишете какой-то фреймворк и поэтому не знаете, есть ли у Window FLAG_SECURE или нет, теоретически вы сможете найти его в результате getAttributes(), хотя я никогда этого не пробовал. И, если вы имеете в виду окно из какого-то другого процесса, я сомневаюсь, что приложение SDK может узнать, имеет ли окно FLAG_SECURE или нет. - person CommonsWare; 17.06.2013
comment
Замечательный и простой ответ! Мне интересно, почему такие приложения, как snapchat, не используют это, чтобы никто не делал скриншот отправленных изображений . - person Shobhit Puri; 25.08.2013
comment
@CommonsWare Надеюсь, у вас все хорошо. У меня есть еще одна проблема, связанная с безопасным флагом. Я установил этот флаг, как вы указали в ответе, и до KitKat он работал хорошо. В KitKat, если я нажму power+volumn_down и поверну устройство, я смогу сделать снимок экрана. Это ошибка в KitKat? Или есть другой способ установить безопасный флаг? Пожалуйста, обновите меня. - person Pankaj Kumar; 22.01.2014
comment
@CommonsWare На самом деле эта проблема не возникает в версии 4.3. Так это ошибка в KitKat? Согласно вашей ссылке, похоже, что это зависит от устройства, верно? - person Pankaj Kumar; 22.01.2014
comment
@PankajKumar: я говорю, что пытался воспроизвести эту проблему, но не смог (см. комментарий № 4 к отчету о проблеме). - person CommonsWare; 22.01.2014
comment
Любая идея, как я могу запретить Android делать снимок экрана, когда он переходит в фоновый режим, но разрешить пользователям делать снимок экрана вручную? Я разместил еще один вопрос: stackoverflow.com/questions/28873633/ - person Wirling; 17.03.2015
comment
@CommonsWare Могу ли я отображать собственные фотографии вместо автоматических снимков экрана в списке последних приложений? - person Dhaval Khant; 24.04.2015
comment
@DhavalKhant: Вы можете попробовать onCreateThumbnail(), хотя я лично не пробовал: developer.android.com/reference/android/app/ - person CommonsWare; 24.04.2015
comment
Просто добавить пакет, потому что это заняло у меня немного времени: WindowManager.LayoutParams.FLAG_SECURE - person Andreas Rudolph; 04.06.2015
comment
Это не работает надежно на Android 5.1, см. code.google.com. /p/android/issues/detail?id=169933 - person petrsyn; 12.09.2015
comment
Да, очевидно, есть какие-то ошибки, еще одна заявка открыта здесь: code.google.com/p/android-developer-preview/issues/ - person Ciprian; 22.09.2015
comment
Есть ли способ установить это в Xamarin? Мне не удалось получить доступ к параметру FLAG_SECURE. - person Emrah Akgül; 22.06.2016
comment
@EmrahAkgül: я едва могу написать Xamarin. :-) Вам лучше задать отдельный вопрос о переполнении стека с соответствующим тегом Xamarin, спрашивая, как его использовать. - person CommonsWare; 22.06.2016
comment
Спасибо за ОБНОВЛЕНИЕ №2, мне бы это в голову не пришло. - person Quark; 18.11.2016
comment
@EmrahAkgül или кто-то еще интересуется Xamarin: Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure); - person Gabriel Bourgault; 25.08.2017
comment
@AjayMistry: FLAG_SECURE работает, как и ожидалось, на Samsung Galaxy S8 под управлением Android 7.0 в ландшафтном режиме. - person CommonsWare; 06.01.2018
comment
@CommonsWare: я переустанавливаю его, но он не работает ... вместо этого он отлично работает в портретном режиме, но когда я переключаю его в ландшафтный режим, он записывает экран ... что мне нужно сделать, чтобы добиться этого ?? - person Ajay Mistry; 09.01.2018
comment
@AjayMistry: свяжитесь с производителем устройства, так как у него есть ошибка. - person CommonsWare; 09.01.2018
comment
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); не работает для Android Pie. - person Rajeev Sahu; 03.10.2018
comment
@ user1182217: Сегодня утром у меня все работало нормально, в тесте на Google Pixel под управлением Android 9.0 (Pie). Не стесняйтесь предоставить ссылку на пример проекта, который может воспроизвести ваши проблемы на Android 9.0. - person CommonsWare; 04.10.2018
comment
@CommonsWare: я пробовал на устройстве One Plus с Android Pie (9.0). Как бы то ни было, FLAG_SECURE отлично работает ниже 9.0. - person Rajeev Sahu; 04.10.2018
comment
@ user1182217: Тогда, возможно, проблема связана с этой конкретной моделью устройства. - person CommonsWare; 04.10.2018
comment
@CommonsWare: Да, вы правы. В пикселях работает нормально. Проблема связана с моделью устройства One Plus. Спасибо. - person Rajeev Sahu; 05.10.2018
comment
вы также можете изучить некоторые возможные улучшения по сравнению с FLAG_SECURE - person Andreas Happe; 24.10.2018

Будьте осторожны при использовании 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);
}

Вот как выглядит зашифрованный экран:

Зашифрованное изображение экрана

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

person gardarh    schedule 20.06.2012
comment
Вы совершенно правы, мы столкнулись с этой проблемой, и она, безусловно, была необходима для проверки уровня API. На самом деле забыл опубликовать это, так что спасибо, что подняли его снова. :) - person StingRay5; 27.06.2012
comment
Это также происходит на Samsung Gio (Gingerbread), но на Froyo все в порядке - поэтому это происходит только на 2.3 - person pixel; 29.10.2012
comment
Мы тоже заметили эту проблему. Вы можете проверить в эмуляторе на устройствах Gingerbread. - person twaddington; 31.12.2012
comment
Я также могу подтвердить, что эта проблема возникает на устройствах Samsung Gingerbread. - person Ernir Erlingsson; 17.04.2013
comment
Даже в более новых версиях Android FLAG_SECURE может быть проблематичным: в Android 4.3 FLAG_SECURE вызывает проблемы с анимацией при повороте экрана, см. code.google.com/p/android/issues/detail?id=58632 — исправлено в Android 4.4. - person Oliver; 23.06.2014
comment
Привет... мне нужно заблокировать снимок экрана для определенного действия. но ваш код подавляет скриншот для всего приложения. - person user3546693; 17.11.2015

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

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

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

person Davideas    schedule 20.03.2015
comment
В моем приложении у меня есть функция установки/снятия FLAG_SECURE на основе предпочтений пользователя. Он работал нормально, пока в переключателе задач не появился KITKAT и черный экран. В Lollipop обзор отображает последний снимок моего приложения, время, когда FLAG_SECURE не был установлен (сброшен). - person r.bhardwaj; 10.04.2015
comment
@r.bhardwaj Я думаю, что в этом случае мы мало что можем сделать, но вы можете посоветовать пользователю, что изменение требует перезапуска приложения, чтобы оно вступило в силу ;-) и все готово. - person Davideas; 17.10.2015
comment
Кто-нибудь нашел способ раздуть пользовательский вид до того, как будет сделан снимок, чтобы это был не просто черный экран? Я пробовал раздувать представление оконного менеджера в onPause, но, похоже, к тому времени уже слишком поздно. - person user1064249; 02.02.2017
comment
Привет @ user1064249 Вы нашли какое-нибудь решение? Я хочу раздуть панель запуска до того, как ОС сделает снимок экрана. - person Alexiscanny; 04.01.2018

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

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

person D. Maul    schedule 24.10.2018

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

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

person Harsh Barnwal    schedule 19.10.2019

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

getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,     
WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.activity_notification);
person Arun Prajapati    schedule 25.01.2020

В случае, если кто-то ищет решение, в котором приложение должно защищать (наложение экрана), когда приложение является фоновым или поддерживает все запущенные приложения, а приложение в приложении должно позволять делать снимки экрана. Попробуйте ниже: -

@Override
    protected void onResume() {
        super.onResume();
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
    }

    @Override
    protected void onPause() {
        super.onResume();
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
    }
person Gaurav    schedule 31.05.2021
comment
Этот способ не работает на некоторых устройствах.. - person hkh114; 22.06.2021