¿Cómo evito que Android tome una captura de pantalla cuando mi aplicación pasa a segundo plano?

146

La aplicación que estoy construyendo actualmente tiene el requisito de que la aplicación tiene que evitar que el sistema operativo tome una captura de pantalla de la aplicación cuando está siendo puesta en segundo plano por razones de seguridad. De esta manera, no podrá ver la última pantalla activa al cambiar de una aplicación a otra.

Estoy planeando poner esta funcionalidad en el método onPause de la clase de aplicación, pero primero necesito descubrir cómo puedo lograr esta funcionalidad.

Entonces, ¿hay alguien por ahí que tenga idea de cómo solucionar esto?

StingRay5
fuente

Respuestas:

264

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

Esto definitivamente protege contra capturas de pantalla manuales y capturas de pantalla automáticas del historial de tareas recientes de ICS. También protege contra la grabación de pantalla (por ejemplo, aplicaciones que usan las API de proyección de medios).

ACTUALIZACIÓN : también protege contra Now On Tap u otros asistentes en Android 6.0; no obtendrán acceso a los detalles de widgets y contenedores en su interfaz de usuario si el usuario abre el asistente.

ACTUALIZACIÓN # 2 : sin embargo, no todo en la actividad estará protegido. Todas las ventanas pop-up - Dialog, Spinner, AutoCompleteTextView, acción barra de desbordamiento, etc. - serán inseguros. Puede solucionar el Dialogproblema invocando getWindow()y configurando FLAG_SECURE. El resto ... se pone complicado. Vea esta publicación de blog para más.

CommonsWare
fuente
66
@ Dany's: En realidad, tiene todo que ver con la pregunta. Acabo de probarlo en un Nexus S (4.0.3), y funciona como se esperaba: la captura de pantalla de tareas recientes se suprime. Aún verá el nombre y el ícono de la aplicación, pero la captura de pantalla es negra. Puede probarlo en el hardware ICS.
CommonsWare
2
@ StingRay5: FLAG_SECUREha existido desde el principio, solo tenía un significado limitado hasta hace poco.
CommonsWare
1
Es interesante notar que hay un método llamado onCreateThumbnail ni el ciclo de vida de la actividad, pero nunca se usa.
Snicolas
2
@PankajKumar: Si el "código para tomar una captura de pantalla" que escribiste es el clásico truco "agarrar el framebuffer como root", FLAG_SECUREno te defenderás de eso, ya que es un nivel demasiado bajo. Del mismo modo, si tomó su propia jerarquía de widgets y la hizo Bitmapretroceder Canvas, FLAG_SECUREprobablemente no se defenderá de eso, ya que está tomando sus propias capturas de pantalla de sus propios widgets y, por lo tanto, presumiblemente quería los "seguros" allí. FLAG_SECUREes para capturas de pantalla del sistema , como las miniaturas de tareas recientes.
CommonsWare
2
Maravillosa y simple respuesta! Me pregunto por qué las aplicaciones como Snapchat no usan esto para evitar que alguien tome una captura de pantalla de las imágenes enviadas.
Shobhit Puri
78

Tenga cuidado al usar WindowManager.LayoutParams.FLAG_SECURE, en algunos dispositivos (verificado en Samsung Galaxy ACE, por ejemplo, GT-S5830), esto hará que la vista sea desordenada. Parece un error específico de Samsung. Recomiendo lo siguiente:

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

Así es como se ve una pantalla codificada:

Imagen de pantalla codificada

Sin embargo, esto funciona correctamente en los teléfonos ICS Samsung, por lo que supongo que el problema está aislado en los dispositivos Gingerbread (o anteriores).

Gardarh
fuente
8
Tiene toda la razón, nos encontramos con este problema, y ​​ciertamente era necesario verificar el nivel de API. En realidad, olvidé publicar esto, así que gracias por mencionarlo nuevamente. :)
StingRay5
También se produce en el Samsung Gio (pan de jengibre), sino en Froyo está bien - por lo que se produce sólo en 2,3
pixel
Notamos este problema también. Puedes verificarlo en el emulador en dispositivos Gingerbread.
twaddington
También puedo confirmar que este problema aparece en los dispositivos Samsung Gingerbread.
Ernir Erlingsson
77
Incluso en las versiones más recientes de Android FLAG_SECURE puede ser problemático: en Android 4.3 FLAG_SECURE causa problemas de animación en la animación de rotación de pantalla, consulte code.google.com/p/android/issues/detail?id=58632 ; esto se ha solucionado en Android 4.4
Oliver
13

La solución proporcionada por CommonsWare sigue siendo válida también en Lollipop.

Solo una nota, si desea continuar sin ver instantáneas en la lista reciente de toda la aplicación, TODAS las actividades implementadas deben especificar en el onCreate()método la marca getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); antessetContentView();

De lo contrario, una instantánea en la lista reciente mostrará la primera actividad sin la bandera si el usuario navegó por ella.

Davideas
fuente
1
En mi aplicación, tengo la funcionalidad de configurar / borrar FLAG_SECURE en función de una preferencia del usuario. Funcionó bien hasta que KITKAT y la pantalla en negro se pueden ver en el conmutador de tareas. En Lollipop, la Descripción general muestra la última instantánea de mi aplicación, la hora en que FLAG_SECURE no se configuró (borró).
r.bhardwaj
@ r.bhardwaj, creo que no podemos hacer mucho en ese caso, pero puede aconsejarle al usuario que, el cambio necesita que la aplicación se reinicie para que surta efecto ;-) y ya está.
Davideas
1
¿Alguien encontró una manera de inflar una vista personalizada antes de tomar una instantánea, por lo que no es solo una pantalla en negro? Intenté inflar una vista en el administrador de ventanas en onPause, pero parece que para entonces es demasiado tarde.
user1064249
Hola @ user1064249 ¿Has encontrado alguna solución? Quiero inflar la vista de inicio antes de que el sistema operativo tome la captura de pantalla
Alexiscanny
1

Aquí hay una solución para ocultar el contenido de una aplicación cubriéndola con una pantalla de inicio cuando la aplicación se pone en segundo plano. Esto no está utilizando la técnica FLAG_SECURE, simplemente anulo los métodos onPause y onResume de las pantallas y modifico la vista para mostrar una que cubra todo en la parte posterior.

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

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

esto funcionó para mí, evita tomar capturas de pantalla y también cualquier aplicación de grabación incorporada o de terceros desde la pantalla de grabación.

Harsh Barnwal
fuente
0

Esto es un trabajo para mí después de agregar estas líneas en onCreate antes de establecerContentView de cada actividad.

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