Comment empêcher Android de prendre une capture d'écran lorsque mon application passe en arrière-plan?

146

L'application que je suis en train de créer exige que l'application empêche le système d'exploitation de prendre une capture d'écran de l'application lorsqu'elle est placée en arrière-plan pour des raisons de sécurité. De cette façon, il ne pourra pas voir le dernier écran actif lors du basculement entre les applications.

Je prévois de mettre cette fonctionnalité dans la méthode onPause de la classe d'application, mais je dois d'abord savoir comment je peux obtenir cette fonctionnalité.

Alors, y a-t-il quelqu'un qui sait comment résoudre ce problème?

StingRay5
la source

Réponses:

264

Essayez 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);
  }
}

Cela protège définitivement contre les captures d'écran manuelles et les captures d'écran automatiques de l'historique des tâches récentes d'ICS. Il protège également contre l'enregistrement d'écran (par exemple, les applications utilisant les API de projection multimédia).

MISE À JOUR : il protège également contre Now On Tap ou d'autres assistants sur Android 6.0; ils n'auront pas accès aux détails des widgets et des conteneurs dans votre interface utilisateur si l'utilisateur ouvre l'assistant.

MISE À JOUR # 2 : cependant, tout dans l'activité ne sera pas protégé. Toutes les fenêtres pop-up - Dialog, Spinner, AutoCompleteTextView, débordement de la barre d'action, etc. - seront en situation d' insécurité. Vous pouvez résoudre le Dialogproblème en l'appelant getWindow()et en définissant FLAG_SECURE. Le reste ... devient délicat. Consultez cet article de blog pour en savoir plus.

CommonsWare
la source
6
@ Dany's: En fait, cela a tout à voir avec la question. Je viens de le tester sur un Nexus S (4.0.3), et cela fonctionne comme prévu - la capture d'écran des tâches récentes est supprimée. Vous voyez toujours le nom et l'icône de l'application, mais la capture d'écran est noire. Vous pouvez l'essayer sur du matériel ICS.
CommonsWare
2
@ StingRay5: FLAG_SECUREexiste depuis le début - il avait juste une signification limitée jusqu'à récemment.
CommonsWare
1
Il est intéressant de noter qu'il existe une méthode appelée onCreateThumbnail ni le cycle de vie de l'activité, mais elle n'est jamais utilisée.
Snicolas
2
@PankajKumar: Si le "code pour prendre une capture d'écran" que vous avez écrit est ce truc classique "prenez le framebuffer en tant que root", FLAG_SECUREne vous défendrez pas contre cela, car c'est trop bas. De même, si vous avez pris votre propre hiérarchie de widgets et l'avez fait dessiner sur un Bitmap-backed Canvas, vous FLAG_SECUREne vous défendrez probablement pas contre cela, car vous prenez vos propres captures d'écran de vos propres widgets et que vous vouliez donc probablement les "sécurisés". FLAG_SECUREest pour les captures d'écran système , telles que les vignettes des tâches récentes.
CommonsWare
2
Réponse merveilleuse et simple! Je me demande pourquoi des applications comme Snapchat ne l'utilisent pas pour empêcher quelqu'un de prendre une capture d'écran des images envoyées.
Shobhit Puri
78

Soyez prudent lorsque vous utilisez WindowManager.LayoutParams.FLAG_SECURE, sur certains appareils (vérifié sur Samsung Galaxy ACE, par exemple GT-S5830) cela rendra la vue brouillée. On dirait un bogue spécifique à Samsung. Je recommande ce qui suit:

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

Voici à quoi ressemble un écran brouillé:

Image d'écran brouillée

Cela fonctionne correctement sur les téléphones ICS Samsung, donc je suppose que le problème est isolé sur les appareils Gingerbread (ou plus anciens).

Gardarh
la source
8
Vous avez tout à fait raison, nous avons rencontré ce problème, et il était certainement nécessaire de vérifier le niveau d'API. En fait, j'ai oublié de publier ceci, alors merci de l'avoir soulevé à nouveau. :)
StingRay5
Cela se produit également sur Samsung Gio (Gingerbread) mais sur Froyo, c'est ok - donc cela ne se produit que sur 2.3
pixel
Nous avons également remarqué ce problème. Vous pouvez vérifier dans l'émulateur sur les appareils Gingerbread.
twaddington
Je peux également confirmer que ce problème apparaît sur les appareils Samsung Gingerbread.
Ernir Erlingsson
7
Même sur les nouvelles versions d'Android, FLAG_SECURE peut être problématique: sur Android 4.3 FLAG_SECURE provoque des problèmes d'animation dans l'animation de rotation de l'écran, voir code.google.com/p/android/issues/detail?id=58632 - cela a été corrigé sur Android 4.4
Oliver
13

La solution fournie par CommonsWare continue d'être valable également dans Lollipop.

Juste une note, si vous souhaitez continuer à ne pas voir les instantanés dans la liste récente pour l' ensemble de l' application, TOUTES les activités implémentées doivent spécifier dans la onCreate()méthode l'indicateur getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); avantsetContentView();

Sinon, un instantané de la liste récente affichera la première activité sans l'indicateur si l'utilisateur l'a parcourue.

Davideas
la source
1
Dans mon application, j'ai la fonctionnalité de définir / effacer FLAG_SECURE en fonction des préférences de l'utilisateur. Cela a bien fonctionné jusqu'à ce que KITKAT et l'écran noir soient visibles dans le sélecteur de tâches. Dans Lollipop, la vue d'ensemble affiche le dernier instantané de mon application, l'heure à laquelle FLAG_SECURE n'a pas été défini (effacé).
r.bhardwaj
@ r.bhardwaj Je pense que nous ne pouvons pas faire grand-chose dans ce cas, mais vous pouvez informer l'utilisateur que le changement doit redémarrer l'application pour prendre pleinement effet ;-) et vous avez terminé.
Davideas
1
Quelqu'un a-t-il trouvé un moyen de gonfler une vue personnalisée avant que l'instantané ne soit pris, donc ce n'est pas seulement un écran noir? J'ai essayé de gonfler une vue sur le gestionnaire de fenêtres dans onPause, mais il semble qu'il soit trop tard.
user1064249
Salut @ user1064249 Avez-vous trouvé une solution? Je veux gonfler la vue du lanceur avant que le système d'exploitation ne prenne la capture d'écran
Alexiscanny
1

Voici une solution pour masquer le contenu d'une application en la recouvrant d'un écran de démarrage lorsque l'application est mise en arrière-plan. Cela n'utilise pas la technique FLAG_SECURE, je remplace simplement les méthodes onPause et onResume des écrans et je modifie la vue pour en afficher une qui couvre tout ce qui se trouve à l'arrière.

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

D. Maul
la source
0
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
            WindowManager.LayoutParams.FLAG_SECURE);

cela a fonctionné pour moi, cela empêche de prendre une capture d'écran et également toute application d'enregistrement intégrée ou tierce de l'écran d'enregistrement.

Barnwal dur
la source
0

C'est un travail pour moi après avoir ajouté ces lignes dans onCreate avant setContentView de chaque activité.

getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,     
WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.activity_notification);
Arun Prajapati
la source