Android: ¿Cómo puedo obtener la actividad actual en primer plano (de un servicio)?

Resuelto George asked hace 54 años • 13 respuestas

¿Existe una forma nativa de Android de obtener una referencia a la actividad que se está ejecutando actualmente desde un servicio?

Tengo un servicio ejecutándose en segundo plano y me gustaría actualizar mi Actividad actual cuando ocurre un evento (en el servicio). ¿Existe una manera fácil de hacerlo (como la que sugerí anteriormente)?

George avatar Jan 01 '70 08:01 George
Aceptado

Actualización : esto ya no funciona con las actividades de otras aplicaciones a partir de Android 5.0


Aquí tienes una buena forma de hacerlo utilizando el administrador de actividades. Básicamente, obtienes las tareas en ejecución del administrador de actividades. Siempre devolverá primero la tarea actualmente activa. Desde allí puedes obtener la actividad superior.

Ejemplo aquí

Existe una forma sencilla de obtener una lista de tareas en ejecución desde el servicio ActivityManager. Puede solicitar una cantidad máxima de tareas que se ejecutan en el teléfono y, de forma predeterminada, la tarea actualmente activa se devuelve primero.

Una vez que lo tenga, puede obtener un objeto ComponentName solicitando topActivity de su lista.

He aquí un ejemplo.

    ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
    Log.d("topActivity", "CURRENT Activity ::" + taskInfo.get(0).topActivity.getClassName());
    ComponentName componentInfo = taskInfo.get(0).topActivity;
    componentInfo.getPackageName();

Necesitará el siguiente permiso en su manifiesto:

<uses-permission android:name="android.permission.GET_TASKS"/>
Nelson Ramirez avatar Jan 20 '2011 22:01 Nelson Ramirez

Advertencia: infracción de Google Play

Google ha amenazado con eliminar aplicaciones de Play Store si utilizan servicios de accesibilidad con fines no relacionados con la accesibilidad. Sin embargo, según se informa, esto se está reconsiderando .


Utilice unAccessibilityService

  • Puede detectar la ventana actualmente activa utilizando un archivo AccessibilityService.
  • En la onAccessibilityEventdevolución de llamada, verifique el tipo de evento para determinar cuándo cambia la ventana actual.TYPE_WINDOW_STATE_CHANGED
  • Compruebe si la ventana es una actividad llamando PackageManager.getActivityInfo().

Beneficios

  • Probado y funcionando en Android 2.2 (API 8) hasta Android 7.1 (API 25).
  • No requiere encuestas.
  • No requiere el GET_TASKSpermiso.

Desventajas

  • Cada usuario debe habilitar el servicio en la configuración de accesibilidad de Android.
  • Esto no es 100% confiable. De vez en cuando los acontecimientos se suceden fuera de orden.
  • El servicio siempre está funcionando.
  • Cuando un usuario intenta habilitar AccessibilityService, no puede presionar el botón Aceptar si una aplicación ha colocado una superposición en la pantalla. Algunas aplicaciones que hacen esto son Velis Auto Brightness y Lux. Esto puede resultar confuso porque es posible que el usuario no sepa por qué no puede presionar el botón o cómo solucionarlo.
  • No AccessibilityServicesabrán la actividad actual hasta el primer cambio de actividad.

Ejemplo

Servicio

public class WindowChangeDetectingService extends AccessibilityService {

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();

        //Configure these here for compatibility with API 13 and below.
        AccessibilityServiceInfo config = new AccessibilityServiceInfo();
        config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
        config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;

        if (Build.VERSION.SDK_INT >= 16)
            //Just in case this helps
            config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;

        setServiceInfo(config);
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            if (event.getPackageName() != null && event.getClassName() != null) {
                ComponentName componentName = new ComponentName(
                    event.getPackageName().toString(),
                    event.getClassName().toString()
                );

                ActivityInfo activityInfo = tryGetActivity(componentName);
                boolean isActivity = activityInfo != null;
                if (isActivity)
                    Log.i("CurrentActivity", componentName.flattenToShortString());
            }
        }
    }

    private ActivityInfo tryGetActivity(ComponentName componentName) {
        try {
            return getPackageManager().getActivityInfo(componentName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            return null;
        }
    }

    @Override
    public void onInterrupt() {}
}

AndroidManifest.xml

Combina esto en tu manifiesto:

<application>
    <service
        android:label="@string/accessibility_service_name"
        android:name=".WindowChangeDetectingService"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService"/>
        </intent-filter>
        <meta-data
            android:name="android.accessibilityservice"
            android:resource="@xml/accessibilityservice"/>
    </service>
</application>

Información de servicio

Pon esto en res/xml/accessibilityservice.xml:

<?xml version="1.0" encoding="utf-8"?>
<!-- These options MUST be specified here in order for the events to be received on first
 start in Android 4.1.1 -->
<accessibility-service
    xmlns:tools="http://schemas.android.com/tools"
    android:accessibilityEventTypes="typeWindowStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagIncludeNotImportantViews"
    android:description="@string/accessibility_service_description"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:ignore="UnusedAttribute"/>

Habilitando el servicio

Cada usuario de la aplicación deberá habilitar explícitamente AccessibilityServicepara poder utilizarla. Consulte esta respuesta de StackOverflow para saber cómo hacer esto.

Tenga en cuenta que el usuario no podrá presionar el botón Aceptar cuando intente habilitar el servicio de accesibilidad si una aplicación ha colocado una superposición en la pantalla, como Velis Auto Brightness o Lux.

Sam avatar Dec 24 '2014 22:12 Sam