En el desarrollo de aplicaciones Android, es común necesitar determinar qué aplicación está actualmente en primer plano. Esto puede ser útil para funcionalidades como monitoreo de uso o restricciones. A continuación, se presentan tres métodos para lograrlo.
1. Uso de ActivityManager con el método getRunningTasks
Este método requiere el permiso GET_TASKS, pero está obsoleto en versiones recientes de Android.
public String obtenerPaqueteEnPrimerPlano(Context context) {
ActivityManager gestorActividades = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tareas = gestorActividades.getRunningTasks(1);
if (!tareas.isEmpty()) {
ComponentName actividadSuperior = tareas.get(0).topActivity;
return actividadSuperior.getPackageName();
}
return null;
}
Agregar en AndroidManifest.xml:
<uses-permission android:name="android.permission.GET_TASKS" />
2. Empleo de UsageStatsManager para aplicaciones recientes
Este enfoque permite obtener el paquete de la aplicación más recientemente usada mediante el servicio de estadísticas de uso. Se necesita el permiso PACKAGE_USAGE_STATS y que el usuario active manualmente el acceso.
public String obtenerPaqueteReciente(Context context) {
UsageStatsManager gestorEstadisticas = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
long tiempoActual = System.currentTimeMillis();
long ventanaTiempo = 30 * 60 * 1000; // 30 minutos en milisegundos
List<UsageStats> listaEstadisticas = gestorEstadisticas.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, tiempoActual - ventanaTiempo, tiempoActual);
if (listaEstadisticas != null && !listaEstadisticas.isEmpty()) {
TreeMap<Long, UsageStats> mapaOrdenado = new TreeMap<>();
for (UsageStats estadisticas : listaEstadisticas) {
mapaOrdenado.put(estadisticas.getLastTimeUsed(), estadisticas);
}
if (!mapaOrdenado.isEmpty()) {
UsageStats masReciente = mapaOrdenado.get(mapaOrdenado.lastKey());
return masReciente.getPackageName();
}
}
return null;
}
Para habilitar el acceso, redirigir al usuario a la configuración:
Intent intento = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
context.startActivity(intento);
Declaración en AndroidManifest.xml:
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
3. Obtención mediante AccessibilityService
Los servicios de accesibilidad pueden interceptar eventos de ventana, lo que permite rastrear la aplicación en primer plano. Este método proporciona tanto el nombre del paquete como el de la actividad.
Primero, declarar el servicio en AndroidManifest.xml:
<service
android:name=".servicio.MonitorAccesibilidad"
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/config_accesibilidad" />
</service>
Crear el archivo de configuración en res/xml/config_accesibilidad.xml:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeWindowStateChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagRetrieveInteractiveWindows"
android:canRetrieveWindowContent="true"
android:canRequestFilterKeyEvents="false"
android:notificationTimeout="100"
android:description="@string/descripcion_accesibilidad" />
Implementar el servicio de accesibilidad:
public class MonitorAccesibilidad extends AccessibilityService {
private String paqueteActual;
private String actividadActual;
@Override
public void onAccessibilityEvent(AccessibilityEvent evento) {
if (evento.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
paqueteActual = evento.getPackageName() != null ? evento.getPackageName().toString() : "";
actividadActual = evento.getClassName() != null ? evento.getClassName().toString() : "";
// Se puede usar paqueteActual para obtener el paquete en primer plano
}
}
@Override
public void onInterrupt() {
// Manejar interrupciones si es necesario
}
}
Este método puede ser detenido por el sistema en algunos dispositivos cuando la aplicación se cierra en segundo plano.