Cómo detectar los clics del botón del sistema “Aplicaciones recientes” (Honeycomb +)

Me pregunto qué método llama este botón.

enter image description here

Mi juego siempre se detiene / reanuda correctamente, excepto cuando uso este botón, parece que este botón no llama a los onPause() y onResume() de una actividad . Funciona si salgo del juego, voy a otra ventana (como la de la imagen) y luego utilizo este botón para reanudar. Pero si presiono este botón, cuando está dentro del juego, el juego se detiene pero el hilo se reanuda como siempre, el juego simplemente permanece en pantalla y parpadea un poco.

Difícil de explicar, pero espero ser claro, si no, ¡pregunta!

Ninguno de los métodos estándar del ciclo de vida de la actividad se invoca cuando se presiona el botón “Aplicaciones recientes”. La actividad permanecerá activa después de la lista de ventanas emergentes de aplicaciones recientes. A través de la parte izquierda semitransparente de esta lista, puede observar que la animación de la aplicación aún se está ejecutando, si está ejecutando un juego con alguna animación que no manejó esta situación correctamente. De hecho, muchos de los juegos en Google Play no manejaron esta situación de manera adecuada, incluso las buenas, como Angry Birds.

El único método de actividad que se llama cuando el usuario abre la lista de “Aplicaciones recientes” (o regresa de él) está onWindowFocusChanged con el parámetro booleano hasFocus . Cuando la lista de usuario abierta del método de aplicación reciente onWindowFocusChanged() llamada con hasFocus es igual a false , y el mismo método llamado con hasFocus es igual a true cuando el usuario presiona Atrás en esta lista.

Me enfrenté a un problema similar, por lo tanto, necesitaba saber cuándo el usuario presiona el botón de aplicaciones recientes (botón de la tecla de menú en las versiones anteriores de android). después de varias horas de investigación, no encontré un evento para atrapar cuando se presiona el botón de inicio o el botón de menú. descubrí que me lleva más tiempo llamar a Detener () cuando el usuario presiona el botón de inicio, por lo que me imagino un truco para distinguir entre estos botones de referencia en relación con el tiempo de respuesta y anulando dos métodos:

@Anular

 public void onUserLeaveHint() { // do stuff super.onUserLeaveHint(); userLeaveTime = System.currentTimeMillis() ; isNotPower = true; } 

@Anular

 public void onStop() { super.onStop(); if (isNotPower) { defStop = System.currentTimeMillis() - userLeaveTime; if (defStop > 200 ) { //home button } if (defStop < 200) { //recent apps button } } isNotPower = false; } 
  • el parámetro isNotPower que es para comprobar que no se presiona el botón de encendido, cuando el botón de encendido presiona el método onStop () se llama pero no th onUserLeaveHint ().

Para detectar cuando se presionó el botón “Aplicaciones recientes”, puede usar el Servicio de accesibilidad. Tendrá que ejecutar su propio Servicio de Accesibilidad y recibir eventos con el tipo “TYPE_WINDOW_STATE_CHANGED” y verificar el nombre de la clase del evento.

  1. Lea sobre el servicio de accesibilidad en el desarrollador de Android. Configure su propio servicio de accesibilidad, pida permiso al usuario.
  2. En su método de anulación del Servicio de Accesibilidad onAccessibilityEvent()
  3. En este método, recibirá el objeto de AccessibilityEvent event , este objeto contiene toda la información necesaria sobre un evento que acaba de ocurrir en su dispositivo.
  4. Estamos interesados ​​en ClassName. ClassName a veces puede ser nulo, así que no te olvides de! = Verificación nula. Los nombres de los paquetes de la ventana de Aplicaciones recientes variarán según la versión de Android:

    • Android 4.1: “com.android.internal.policy.impl.RecentApplicationsDialog”
    • Android 4.2 – 4.4: “com.android.systemui.recent.RecentsActivity”
    • Android 5.0 – 7.1: “com.android.systemui.recents.RecentsActivity” (se agregó la letra “s”)

No sé el nombre de clase para dispositivos más antiguos, pero no creo que alguien los mantenga en 2017;)

Entonces tendrás algo como esto:

 @Override public void onAccessibilityEvent(AccessibilityEvent event) { if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || event.getClassName() == null) return; String className = String.valueOf(event.getClassName()); if (className.equals("com.android.internal.policy.impl.RecentApplicationsDialog") || className.equals("com.android.systemui.recent.RecentsActivity") || className.equals("com.android.systemui.recents.RecentsActivity")){ //Recent button was pressed. Do something. } } 

Lo probé en los siguientes dispositivos reales: LG, Nexus, Sony y dispositivos virtuales: Motorola, Samsung.

Si alguien conoce una excepción para estos nombres de clases, por favor sígueme.

Tengo el mismo problema, resolví este problema como below.er

Botón de registro haga clic en la transmisión para Inicio y RecienteApp

 InnerReceiver mReceiver = new InnerReceiver(); IntentFilter mFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); registerReceiver(mReceiver, mFilter); 

Ahora el código de BroadcastReceiver

 class InnerReceiver extends BroadcastReceiver { final String SYSTEM_DIALOG_REASON_KEY = "reason"; final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY); if (reason != null) { if (mListener != null) { if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) { // Home Button click } else if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { // RecentApp or Overview Button click } } } } } } 

Pero no olvidó unregisterReceiver de unregisterReceiver BroadcastReceiver

La mejor forma que he encontrado es la de Broadcast Action llamada “ACTION_CLOSE_SYSTEM_DIALOGS” .De Google Docs:

Acción de difusión: se transmite cuando una acción del usuario debe solicitar un diálogo de sistema temporal para descartar. Algunos ejemplos de diálogos de sistema temporales son el cuadro de diálogo de notificaciones y el cuadro de diálogo de tareas recientes .

Código de trabajo:

 IntentFilter intentFilterACSD = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { //do what you want here } } }; this.registerReceiver(broadcastReceiver, intentFilterACSD); 

¿Es este el único problema con este juego específico? ¿O es con cada juego que juegas?

Además de onPause() y onResume() , hay otro ciclo llamado onStop() . Tal vez hay algunas cosas fundamentales que se están haciendo aquí. Con solo presionar el botón “Windows-open”, el juego probablemente no ingrese a ” onStop state” mientras que presionar el botón “home” lo hará.

prueba este:

 public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); Log.d("Focus debug", "Focus changed !"); if (!hasFocus) { Log.d("Focus debug", "Lost focus !"); } }