Android 5.1.1 y versiones posteriores – getRunningAppProcesses () solo devuelve mi paquete de aplicaciones

Parece que Google finalmente cerró todas las puertas para obtener el paquete actual de aplicaciones en primer plano.

Después de la actualización de Lollipop, que mató a getRunningTasks(int maxNum) y gracias a esta respuesta , utilicé este código para obtener el paquete de aplicaciones de primer plano desde Lollipop:

 final int PROCESS_STATE_TOP = 2; RunningAppProcessInfo currentInfo = null; Field field = null; try { field = RunningAppProcessInfo.class.getDeclaredField("processState"); } catch (Exception ignored) { } ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE); List appList = am.getRunningAppProcesses(); for (RunningAppProcessInfo app : appList) { if (app.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && app.importanceReasonCode == 0 ) { Integer state = null; try { state = field.getInt( app ); } catch (Exception ignored) { } if (state != null && state == PROCESS_STATE_TOP) { currentInfo = app; break; } } } return currentInfo; 

Android 5.1.1 y superior (6.0 Marshmallow), al parecer, mató a getRunningAppProcesses() también. Ahora devuelve una lista de su propio paquete de aplicación.


UsageStatsManager

Podemos usar la nueva API de UsageStatsManager como se describe aquí, pero no funciona para todas las aplicaciones. Algunas aplicaciones del sistema devolverán el mismo paquete

 com.google.android.googlequicksearchbox 

AccessibilityService (diciembre de 2017: va a ser prohibido para su uso por Google)

Algunas aplicaciones usan AccessibilityService (como se ve aquí ) pero tiene algunas desventajas.


¿Hay alguna otra manera de obtener el paquete actual de la aplicación en ejecución?

Para obtener una lista de procesos en ejecución en Android 1.6 – Android 6.0, puede usar esta biblioteca que escribí: https://github.com/jaredrummler/AndroidProcesses La biblioteca lee / proc para obtener información del proceso.

Google ha restringido significativamente el acceso a / proc en Android Nougat. Para obtener una lista de los procesos en ejecución en Android Nougat, necesitará usar UsageStatsManager o tener acceso a la raíz.

Haga clic en el historial de edición para soluciones alternativas anteriores.

  private String printForegroundTask() { String currentApp = "NULL"; if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats"); long time = System.currentTimeMillis(); List appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*1000, time); if (appList != null && appList.size() > 0) { SortedMap mySortedMap = new TreeMap(); for (UsageStats usageStats : appList) { mySortedMap.put(usageStats.getLastTimeUsed(), usageStats); } if (mySortedMap != null && !mySortedMap.isEmpty()) { currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName(); } } } else { ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE); List tasks = am.getRunningAppProcesses(); currentApp = tasks.get(0).processName; } Log.e("adapter", "Current App in foreground is: " + currentApp); return currentApp; } 

Use este método para obtener una tarea en primer plano. U necesitará un permiso del sistema “android: get_usage_stats”

 public static boolean needPermissionForBlocking(Context context){ try { PackageManager packageManager = context.getPackageManager(); ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0); AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName); return (mode != AppOpsManager.MODE_ALLOWED); } catch (PackageManager.NameNotFoundException e) { return true; } } 

SI el usuario lo habilita en la configuración -> Seguridad -> aplicación con acceso de uso. Después de eso obtendrás la tarea de primer plano. Proceso similar Clean matser por Cheetahamobile google play link

Eche un vistazo a https://github.com/ricvalerio/foregroundappchecker , podría ser lo que necesita. Proporciona código de muestra y elimina el dolor de tener que implementar el detector de primer plano de la versión cruzada.

Aquí hay dos muestras:

 AppChecker appChecker = new AppChecker(); String packageName = appChecker.getForegroundApp(); 

O verifique regularmente:

 AppChecker appChecker = new AppChecker(); appChecker .when("com.other.app", new AppChecker.Listener() { @Override public void onForeground(String packageName) { // do something } ) .when("com.my.app", new AppChecker.Listener() { @Override public void onForeground(String packageName) { // do something } ) .other(new AppChecker.Listener() { @Override public void onForeground(String packageName) { // do something } ) .timeout(1000) .start(this); 

Google limitó esta funcionalidad solo para aplicaciones de sistema. Como se informó en un ticket de error , necesitará el permiso REAL_GET_TASKS para acceder allí.

Las aplicaciones ahora deben tener … permiso.REAL_GET_TASKS para poder obtener información del proceso para todas las aplicaciones. Solo se devolverá la información de proceso para la aplicación de llamada si la aplicación no tiene el permiso. Las aplicaciones Privileges podrán obtener temporalmente información de proceso para todas las aplicaciones si no tienen el nuevo permiso, pero han dejado de tener en cuenta … permission.GET_TASKS Además, solo las aplicaciones del sistema pueden adquirir el permiso REAL_GET_TASKS.

 public class AccessibilityDetectingService 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(final AccessibilityEvent event) { if (event == null ) { return; } else if(event.getPackageName() == null && event.getClassName() == null){ return; } if (activityInfo != null){ Log.d("CurrentActivity", componentName.flattenToShortString()); } } private ActivityInfo tryGetActivity(ComponentName componentName) { try { return getPackageManager().getActivityInfo(componentName, 0); } catch (PackageManager.NameNotFoundException e) { return null; } } @Override public void onInterrupt() { } } }//`enter code here`uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />  

Luego, inicie el servicio y la accesibilidad de la aplicación en la configuración de su dispositivo-> accesibilidad-> Aplicación en ese servicio.

Simplemente lanzando una posible optimización a lo que imagino es un fragmento de código pegado en gran medida para detectar la aplicación más utilizada en Android M.

Esta

 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats"); long time = System.currentTimeMillis(); List appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*1000, time); if (appList != null && appList.size() > 0) { SortedMap mySortedMap = new TreeMap(); for (UsageStats usageStats : appList) { mySortedMap.put(usageStats.getLastTimeUsed(), usageStats); } if (mySortedMap != null && !mySortedMap.isEmpty()) { currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName(); } } } 

Se puede simplificar a esto

 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { UsageStatsManager usm = (UsageStatsManager) context.getSystemService( Context.USAGE_STATS_SERVICE); long time = System.currentTimeMillis(); List appStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1000, time); if (appStatsList != null && !appStatsList.isEmpty()) { currentApp = Collections.max(appStatsList, (o1, o2) -> Long.compare(o1.getLastTimeUsed(), o2.getLastTimeUsed())).getPackageName(); } } 

Me encontré usando este código en un bucle de 2 segundos, y me pregunté por qué estaba usando una solución compleja que era O (n * log (n)) cuando una solución más simple estaba disponible en Collections.max () que es O (n )

Intente utilizar getRunningServices() lugar del método getRunningAppProcesses() .

  ActivityManager mActivityManager = (ActivityManager) getSy stemService(Context.ACTIVITY_SERVICE); List appProcessInfoList = mActivityManager.getRunningServices(Integer.MAX_VALUE);