Determinación de la aplicación de primer plano actual de una tarea o servicio de fondo

Deseo tener una aplicación que se ejecuta en segundo plano, que sabe cuando se está ejecutando alguna de las aplicaciones integradas (mensajería, contactos, etc).

Así que mis preguntas son:

  1. Cómo debo ejecutar mi aplicación en segundo plano.

  2. Cómo mi aplicación de fondo puede saber qué es la aplicación que se ejecuta actualmente en primer plano.

Las respuestas de la gente con experiencia sería muy apreciada.

Con respecto a "2. Cómo mi aplicación de fondo puede saber lo que la aplicación que se ejecuta actualmente en primer plano es".

No utilice el método getRunningAppProcesses() ya que esto devuelve todo tipo de basura del sistema de mi experiencia y obtendrá varios resultados que tienen RunningAppProcessInfo.IMPORTANCE_FOREGROUND . Use getRunningTasks() lugar

Este es el código que utilizo en mi servicio para identificar la aplicación de primer plano actual, es realmente fácil:

 ActivityManager am = (ActivityManager) AppService.this.getSystemService(ACTIVITY_SERVICE); // The first in the list of RunningTasks is always the foreground task. RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0); 

Eso es, entonces usted puede acceder fácilmente a los detalles de la aplicación de primer plano / actividad:

 String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName(); PackageManager pm = AppService.this.getPackageManager(); PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0); String foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString(); 

Esto requiere un permiso adicional en la actividad menifest y funciona perfectamente.

 <uses-permission android:name="android.permission.GET_TASKS" /> 

Tuve que averiguar la solución correcta de la manera más difícil. El siguiente código es parte de cyanogenmod7 (los ajustes de la tableta) y se prueba en android 2.3.3 / pan de jengibre.

Métodos:

  • GetForegroundApp – devuelve la aplicación de primer plano.
  • GetActivityForApp: devuelve la actividad de la aplicación encontrada.
  • IsStillActive – determina si una aplicación encontrada anteriormente sigue siendo la aplicación activa.
  • IsRunningService – una función de ayuda para getForegroundApp

Esto con suerte responde a este problema en todo extend (:

 private RunningAppProcessInfo getForegroundApp() { RunningAppProcessInfo result=null, info=null; if(mActivityManager==null) mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE); List <RunningAppProcessInfo> l = mActivityManager.getRunningAppProcesses(); Iterator <RunningAppProcessInfo> i = l.iterator(); while(i.hasNext()){ info = i.next(); if(info.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && !isRunningService(info.processName)){ result=info; break; } } return result; } private ComponentName getActivityForApp(RunningAppProcessInfo target){ ComponentName result=null; ActivityManager.RunningTaskInfo info; if(target==null) return null; if(mActivityManager==null) mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE); List <ActivityManager.RunningTaskInfo> l = mActivityManager.getRunningTasks(9999); Iterator <ActivityManager.RunningTaskInfo> i = l.iterator(); while(i.hasNext()){ info=i.next(); if(info.baseActivity.getPackageName().equals(target.processName)){ result=info.topActivity; break; } } return result; } private boolean isStillActive(RunningAppProcessInfo process, ComponentName activity) { // activity can be null in cases, where one app starts another. for example, astro // starting rock player when a move file was clicked. we dont have an activity then, // but the package exits as soon as back is hit. so we can ignore the activity // in this case if(process==null) return false; RunningAppProcessInfo currentFg=getForegroundApp(); ComponentName currentActivity=getActivityForApp(currentFg); if(currentFg!=null && currentFg.processName.equals(process.processName) && (activity==null || currentActivity.compareTo(activity)==0)) return true; Slog.i(TAG, "isStillActive returns false - CallerProcess: " + process.processName + " CurrentProcess: " + (currentFg==null ? "null" : currentFg.processName) + " CallerActivity:" + (activity==null ? "null" : activity.toString()) + " CurrentActivity: " + (currentActivity==null ? "null" : currentActivity.toString())); return false; } private boolean isRunningService(String processname){ if(processname==null || processname.isEmpty()) return false; RunningServiceInfo service; if(mActivityManager==null) mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE); List <RunningServiceInfo> l = mActivityManager.getRunningServices(9999); Iterator <RunningServiceInfo> i = l.iterator(); while(i.hasNext()){ service = i.next(); if(service.process.equals(processname)) return true; } return false; } 

Pruebe el siguiente código:

 ActivityManager activityManager = (ActivityManager) newContext.getSystemService( Context.ACTIVITY_SERVICE ); List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); for(RunningAppProcessInfo appProcess : appProcesses){ if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){ Log.i("Foreground App", appProcess.processName); } } 

Nombre del proceso es el nombre del paquete de la aplicación que se ejecuta en primer plano. Compárelo con el nombre del paquete de su aplicación. Si es el mismo entonces su aplicación se ejecuta en primer plano.

Espero que esto responda tu pregunta.

Desde piruleta en adelante esto cambió. Por favor, consulte el código a continuación, antes de que el usuario tiene que ir a Configuración -> Seguridad -> (Desplácese hasta el último) Aplicaciones con acceso de uso -> Dar los permisos a nuestra aplicación

 private void printForegroundTask() { String currentApp = "NULL"; if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE); long time = System.currentTimeMillis(); List<UsageStats> appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*1000, time); if (appList != null && appList.size() > 0) { SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>(); 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<ActivityManager.RunningAppProcessInfo> tasks = am.getRunningAppProcesses(); currentApp = tasks.get(0).processName; } Log.e(TAG, "Current App in foreground is: " + currentApp); } 

La clase ActivityManager es la herramienta adecuada para ver qué procesos se están ejecutando.

Para ejecutar en segundo plano, normalmente desea utilizar un servicio .

Con el fin de determinar la aplicación de primer plano, puede utilizar para detectar la aplicación de primer plano, puede utilizar https://github.com/ricvalerio/foregroundappchecker . Utiliza diferentes métodos dependiendo de la versión androide del dispositivo.

En cuanto al servicio, el repo también proporciona el código que necesita para ello. Esencialmente, deje que android studio cree el servicio para usted, y luego onCreate agregue el fragmento que usa appChecker. Sin embargo, tendrá que pedir permiso.

En lollipop y hasta:

Añadir a mainfest:

 <uses-permission android:name="android.permission.GET_TASKS" /> 

Y hacer algo como esto:

 if( mTaskId < 0 ) { List<AppTask> tasks = mActivityManager.getAppTasks(); if( tasks.size() > 0 ) mTaskId = tasks.get( 0 ).getTaskInfo().id; } 

Teniendo en cuenta que getRunningTasks() es obsoleto y getRunningAppProcesses() no es confiable, llegué a una solución para combinar 2 enfoques mencionados en StackOverflow:

  private boolean isAppInForeground(Context context) { if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE); ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0); String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName(); return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase()); } else { ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo(); ActivityManager.getMyMemoryState(appProcessInfo); if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE) { return true; } KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); // App is foreground, but screen is locked, so show notification return km.inKeyguardRestrictedInputMode(); } } 

Haga algo como esto:

 int showLimit = 20; /* Get all Tasks available (with limit set). */ ActivityManager mgr = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> allTasks = mgr.getRunningTasks(showLimit); /* Loop through all tasks returned. */ for (ActivityManager.RunningTaskInfo aTask : allTasks) { Log.i("MyApp", "Task: " + aTask.baseActivity.getClassName()); if (aTask.baseActivity.getClassName().equals("com.android.email.activity.MessageList")) running=true; } 

Esto funcionó para mí. Pero sólo da el nombre del menú principal. Es decir, si el usuario ha abierto la pantalla Configuración -> Bluetooth -> Nombre del dispositivo, RunningAppProcessInfo lo llama como sólo Configuración. No es capaz de profundizar furthur

 ActivityManager activityManager = (ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE ); PackageManager pm = context.getPackageManager(); List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); for(RunningAppProcessInfo appProcess : appProcesses) { if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(appProcess.processName, PackageManager.GET_META_DATA)); Log.i("Foreground App", "package: " + appProcess.processName + " App: " + c.toString()); } } 

Así es como estoy comprobando si mi aplicación está en primer plano. Nota Estoy utilizando AsyncTask según lo sugerido por la documentación oficial de Android.

  private class CheckIfForeground extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... voids) { ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { Log.i("Foreground App", appProcess.processName); if (mContext.getPackageName().equalsIgnoreCase(appProcess.processName)) { Log.i(Constants.TAG, "foreground true:" + appProcess.processName); foreground = true; // close_app(); } } } Log.d(Constants.TAG, "foreground value:" + foreground); if (foreground) { foreground = false; close_app(); Log.i(Constants.TAG, "Close App and start Activity:"); } else { //if not foreground close_app(); foreground = false; Log.i(Constants.TAG, "Close App"); } return null; } } 

Y ejecute AsyncTask como este. new CheckIfForeground().execute();

Combiné dos soluciones en un método y funciona para mí para API 24 y para API 21. Otros no probé.

El código en Kotlin:

 private fun isAppInForeground(context: Context): Boolean { val appProcessInfo = ActivityManager.RunningAppProcessInfo() ActivityManager.getMyMemoryState(appProcessInfo) if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE) { return true } else if (appProcessInfo.importance == IMPORTANCE_TOP_SLEEPING || appProcessInfo.importance == IMPORTANCE_BACKGROUND) { return false } val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val foregroundTaskInfo = am.getRunningTasks(1)[0] val foregroundTaskPackageName = foregroundTaskInfo.topActivity.packageName return foregroundTaskPackageName.toLowerCase() == context.packageName.toLowerCase() } 

Y en Manifest

 <!-- Check whether app in background or foreground --> <uses-permission android:name="android.permission.GET_TASKS" /> 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.