studio stop startservice servicios servicio segundo primer plano implementar crear aplicacion android

android - stop - Determinar la aplicación en primer plano actual desde una tarea o servicio en segundo plano



startservice android studio (13)

Deseo tener una aplicación que se ejecute en segundo plano, que sabe cuándo se está ejecutando alguna de las aplicaciones integradas (mensajes, contactos, etc.).

Entonces mis preguntas son:

  1. Cómo debería ejecutar mi aplicación en segundo plano.

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

Las respuestas de personas con experiencia serán muy apreciadas.


Así es como estoy comprobando si mi aplicación está en primer plano. Tenga en cuenta que estoy usando AsyncTask como lo sugiere 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 ejecuta AsyncTask así. new CheckIfForeground().execute();


Combiné dos soluciones en un método y funciona para mí para API 24 y para API 21. Otras no las evalué.

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 Manifiesto

<!-- Check whether app in background or foreground --> <uses-permission android:name="android.permission.GET_TASKS" />


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

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

Este es el código que uso 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 todo, entonces puede acceder fácilmente a los detalles de la aplicación / actividad en primer plano:

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" />


Desde lollipop en adelante, esto cambió. Por favor, encuentre el código a continuación, antes de que ese usuario tenga que ir a Configuración -> Seguridad -> (Desplácese hacia abajo hasta la última) Aplicaciones con acceso de uso -> Dele 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); }


En lollipop y arriba:

Agregar a mainfest:

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

Y haz algo como esto:

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


Esto funcionó para mí. Pero solo da el nombre del menú principal. Es decir, si el usuario abrió la pantalla Configuración -> Bluetooth -> Nombre del dispositivo, RunningAppProcessInfo lo llama como solo Configuración. No se puede profundizar en 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()); } }


Haz 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; }


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

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


Para determinar la aplicación en primer plano, que puede usar para detectar la aplicación en primer plano, puede usar github.com/ricvalerio/foregroundappchecker . Utiliza diferentes métodos según la versión de Android del dispositivo.

En cuanto al servicio, el repositorio 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 el appChecker. Sin embargo, deberá solicitar permiso.


Para los casos en que necesitamos verificar desde nuestro propio servicio / hilo de fondo si nuestra aplicación está en primer plano o no. Así es como lo implementé, y funciona bien para mí:

public class TestApplication extends Application implements Application.ActivityLifecycleCallbacks { public static WeakReference<Activity> foregroundActivityRef = null; @Override public void onActivityStarted(Activity activity) { foregroundActivityRef = new WeakReference<>(activity); } @Override public void onActivityStopped(Activity activity) { if (foregroundActivityRef != null && foregroundActivityRef.get() == activity) { foregroundActivityRef = null; } } // IMPLEMENT OTHER CALLBACK METHODS }

Ahora, para consultar otras clases, ya sea que la aplicación esté en primer plano o no, simplemente llame a:

if(TestApplication.foregroundActivityRef!=null){ // APP IS IN FOREGROUND! // We can also get the activity that is currently visible! }


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áralo con el nombre del paquete de tu aplicación. Si es lo mismo, su aplicación se ejecuta en primer plano.

Espero que esto responda tu pregunta.


Teniendo en cuenta que getRunningTasks() está en desuso y getRunningAppProcesses() no es confiable, tomé la decisión de combinar 2 enfoques mencionados en :

private boolean isAppInForeground(Context context) { if (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(); } }


tuve que encontrar 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 / gingerbread.

métodos:

  • getForegroundApp - devuelve la aplicación en 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 auxiliar para getForegroundApp

esto con suerte responde a este problema en todos los sentidos (:

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; }