Jak zapobiec wykonywaniu zrzutu ekranu przez Androida, gdy moja aplikacja działa w tle?

146

Aplikacja, którą obecnie tworzę, ma wymaganie, aby aplikacja uniemożliwiła systemowi operacyjnemu wykonanie zrzutu ekranu aplikacji, gdy jest ona umieszczana w tle ze względów bezpieczeństwa. W ten sposób nie będzie mógł zobaczyć ostatniego aktywnego ekranu podczas przełączania się między aplikacjami.

Planuję umieścić tę funkcjonalność w metodzie onPause klasy aplikacji, ale najpierw muszę dowiedzieć się, jak mogę to osiągnąć.

Więc czy jest tam ktoś, kto ma wskazówkę, jak to naprawić?

StingRay5
źródło

Odpowiedzi:

264

Spróbuj 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);
  }
}

To zdecydowanie zabezpiecza przed ręcznymi zrzutami ekranu i automatycznymi zrzutami ekranu z historii ostatnich zadań ICS. Zabezpiecza również przed nagrywaniem ekranu (np. Aplikacje korzystające z interfejsów API projekcji multimediów).

UPDATE : zabezpiecza również przed Now On Tap lub innymi asystentami w systemie Android 6.0; nie uzyskają dostępu do szczegółów widżetów i kontenerów w Twoim interfejsie użytkownika, jeśli użytkownik wywoła asystenta.

AKTUALIZACJA # 2 : jednak nie wszystko w działaniu będzie chronione. Jakiekolwiek okna pop-up - Dialog, Spinner, AutoCompleteTextView, akcja bar przelewowy, itp - będzie niepewny. Możesz rozwiązać Dialogproblem, dzwoniąc getWindow()do niego i ustawiając FLAG_SECURE. Reszta ... staje się trudna. Więcej informacji znajdziesz w tym poście na blogu .

CommonsWare
źródło
6
@ Dany's: Właściwie to wszystko ma związek z pytaniem. Właśnie przetestowałem to na Nexusie S (4.0.3) i działa zgodnie z oczekiwaniami - zrzut ekranu ostatnich zadań jest wyłączony. Nadal widzisz nazwę i ikonę aplikacji, ale zrzut ekranu jest czarny. Zapraszamy do wypróbowania go na sprzęcie ICS.
CommonsWare
2
@ StingRay5: FLAG_SECUREistnieje od początku - do niedawna miało ograniczone znaczenie.
CommonsWare
1
Warto zauważyć, że istnieje metoda o nazwie onCreateThumbnail ni określająca cykl życia czynności, ale nigdy nie jest używana.
Snicolas
2
@PankajKumar: Jeśli napisany przez Ciebie „kod do zrobienia zrzutu ekranu” jest klasyczną sztuczką polegającą na „złapaniu bufora ramki jako roota”, FLAG_SECUREnie obroni się przed tym, ponieważ jest to zbyt niski poziom. Podobnie, jeśli wziąłeś własną hierarchię widżetów i Bitmapmiałeś ją przyciągnąć do -back-back Canvas, FLAG_SECUREprawdopodobnie nie będziesz się przed tym bronił, ponieważ robisz własne zrzuty ekranu swoich własnych widżetów i dlatego prawdopodobnie chciałeś mieć tam „bezpieczne”. FLAG_SECUREdotyczy zrzutów ekranu systemu , takich jak miniatury ostatnich zadań.
CommonsWare
2
Cudowna i prosta odpowiedź! Zastanawiam się, dlaczego aplikacje takie jak snapchat nie używają tego, aby uniemożliwić komuś zrobienie zrzutu ekranu z wysłanymi obrazami.
Shobhit Puri,
78

Uważaj przy korzystaniu z WindowManager.LayoutParams.FLAG_SECURE, na niektórych urządzeniach (zweryfikowanych na Samsung Galaxy ACE, np. GT-S5830) spowoduje to zakodowanie widoku. Wygląda na konkretny błąd firmy Samsung. Polecam:

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

Tak wygląda zakodowany ekran:

Zakodowany obraz ekranu

Działa to jednak poprawnie na telefonach ICS Samsung, więc zakładam, że problem dotyczy urządzeń Gingerbread (lub starszych).

gardarh
źródło
8
Masz całkowitą rację, natknęliśmy się na ten problem i na pewno był potrzebny do sprawdzenia poziomu API. Właściwie zapomniałem o tym opublikować, więc dziękuję za powtórzenie tego. :)
StingRay5
Występuje również na Samsung Gio (Gingerbread), ale na Froyo jest ok - więc występuje tylko na 2,3
pikselu
Zauważyliśmy również ten problem. Możesz zweryfikować w emulatorze na urządzeniach Gingerbread.
twaddington
Mogę też potwierdzić, że ten problem pojawia się na urządzeniach Samsung Gingerbread.
Ernir Erlingsson
7
Nawet na nowszych wersjach Androida FLAG_SECURE może być problematyczne: na Androidzie 4.3 FLAG_SECURE powoduje problemy z animacją w animacji obracania ekranu, patrz code.google.com/p/android/issues/detail?id=58632 - zostało to naprawione na Androidzie 4.4
Oliver
13

Rozwiązanie dostarczone przez CommonsWare nadal działa również w Lollipop.

Uwaga, jeśli nadal chcesz nie widzieć migawek na najnowszej liście dla całej aplikacji, WSZYSTKIE zaimplementowane działania powinny określać w onCreate()metodzie flagę getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); przedsetContentView();

W przeciwnym razie migawka na ostatnio wyświetlanej liście pokaże pierwsze działanie bez flagi, jeśli użytkownik nawigował po niej.

Davideas
źródło
1
W mojej aplikacji mam funkcję ustawiania / czyszczenia FLAG_SECURE na podstawie preferencji użytkownika. Działało dobrze, dopóki KITKAT i czarny ekran były widoczne w przełączniku zadań. W Lollipop Przegląd wyświetla ostatnią migawkę mojej aplikacji, czas, w którym opcja FLAG_SECURE nie została ustawiona (wyczyszczona).
r.bhardwaj
@ r.bhardwaj Myślę, że w takim przypadku nie możemy zrobić tak wiele, ale możesz doradzić użytkownikowi, że zmiana wymaga ponownego uruchomienia aplikacji, aby w pełni obowiązywała ;-) i gotowe.
Davideas,
1
Czy ktoś znalazł sposób na zawyżenie niestandardowego widoku przed wykonaniem migawki, aby nie był to tylko czarny ekran? Próbowałem zawyżać widok menedżera okien w onPause, ale wydaje się, że jest już za późno.
user1064249
Cześć @ user1064249 Czy znalazłeś jakieś rozwiązanie? Chcę nadmuchać widok Launchera, zanim system operacyjny zrobi zrzut ekranu
Alexiscanny
1

Oto rozwiązanie umożliwiające ukrycie zawartości aplikacji poprzez zakrycie jej ekranem powitalnym, gdy aplikacja jest umieszczona w tle. To nie jest technika FLAG_SECURE, po prostu nadpisuję metody onPause i onResume ekranów i modyfikuję widok, aby pokazywał taki, który obejmuje wszystko z tyłu.

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

D. Maul
źródło
0
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
            WindowManager.LayoutParams.FLAG_SECURE);

to zadziałało dla mnie, zapobiega robieniu zrzutu ekranu, a także każdej wbudowanej lub innej aplikacji do nagrywania z ekranu nagrywania.

Harsh Barnwal
źródło
0

To działa dla mnie po dodaniu tych linii do onCreate przed setContentView każdego działania.

getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,     
WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.activity_notification);
Arun Prajapati
źródło