lollipop - android marshmallow
getRunningTasks no funciona en Android L (5)
En Android L, Google ha desactivado getRunningTasks. Ahora solo puede devolver la tarea propia de aplicaciones y el iniciador doméstico. Ya no puedo obtener otras tareas de aplicaciones. Nuestra aplicación necesita ese método para determinar la aplicación superior actual. ¿Alguien tiene otro método para hacer esto?
He buscado en Google, no hay más temas sobre esto excepto esto: https://code.google.com/p/android-developer-preview/issues/detail?id=29
Aquí hay una solución exacta para obtener la máxima actividad actual en sus dispositivos Android L / Lollipop y dispositivos Android M / Marshmallow.
Primero llame a esta línea de código: (Una vez)
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
El código anterior abrirá una pantalla llamada "Aplicaciones con acceso de uso". Simplemente marque el botón de opción para activar / Ver para permitir el acceso al uso. Ahora llame al siguiente método en su servicio o en cualquier lugar que desee:
public void getTopActivtyFromLolipopOnwards() {
String topPackageName;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
// We get usage stats for the last 10 seconds
List < UsageStats > stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);
// Sort the stats by the last time used
if (stats != null) {
SortedMap < Long, UsageStats > mySortedMap = new TreeMap < Long, UsageStats > ();
for (UsageStats usageStats: stats) {
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
}
if (mySortedMap != null && !mySortedMap.isEmpty()) {
topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
Log.e("TopPackage Name", topPackageName);
}
}
}
}
agregar permiso
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
Esto devolverá el nombre del paquete de la actividad actualmente en ejecución, ya sea Facebook o WhatsApp.
La única complicación de este método es que debe solicitar al usuario que permita las estadísticas de uso de la aplicación ... es decir, el primer paso.
¡Esperanza! esto ayuda a todos
Como mencionó MKY, el método getRunningTasks()
no funciona para obtener la aplicación actual en Lollipop.
Como sunxin8086 escribió, la única forma de obtener las aplicaciones en ejecución es mediante el uso del método getRunningAppsProcesses()
. Sin embargo, la condición info.importance == IMPORTANCE_FOREGROUND
no puede determinar la aplicación actual de forma exclusiva.
El mejor enfoque para determinar la aplicación en primer plano actual puede ser verificar el campo RunningAppProcessInfo
en el objeto RunningAppProcessInfo
. Este campo es un campo oculto, pero puede verlo en la clase RunningAppProcessInfo
. Si este valor es ActivityManager.PROCESS_STATE_TOP
(que también es constante estática oculta), el proceso es el proceso actual en primer plano.
Por ejemplo, el código es
final int PROCESS_STATE_TOP = 2;
ActivityManager.RunningAppProcessInfo currentInfo = null;
Field field = null;
try {
field = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");
} catch (Exception ignored) {
}
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appList = am.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo app : appList) {
if (app.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
&& app.importanceReasonCode == ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN) {
Integer state = null;
try {
state = field.getInt(app);
} catch (Exception e) {
}
if (state != null && state == PROCESS_STATE_TOP) {
currentInfo = app;
break;
}
}
}
return currentInfo;
Nota: el campo processState
no existe en pre-Lolipop. Compruebe que Build.VERSION.SDK_INT >= 21
antes de ejecutar el código anterior. El código anterior funciona solo para Lollipop +.
El otro enfoque, de Gaston (que es bastante diferente), y el significado de ''aplicación actual'' es ligeramente diferente de este enfoque.
Por favor, elija uno para su propósito.
[EDITAR]
Como Sam señaló, modifiqué START_TASK_TO_FRONT
por PROCESS_STATE_TOP
. (Ambos valores son 2)
[EDIT2]
¡Sam tiene un nuevo hallazgo! Para determinar la aplicación en primer plano de forma única, una condición más
process.importanceReasonCode == 0
es necesario. El código anterior ha sido actualizado. ¡Gracias!
Creo que no es posible obtener las tareas de otras aplicaciones,
Esto es lo que dice la documentación
Con la introducción de la nueva función de tareas concurrentes de documentos y actividades en la próxima versión (consulte Documentos concurrentes y actividades en la pantalla Recientes a continuación ), el método ActivityManager.getRecentTasks() ahora está en desuso para mejorar la privacidad del usuario. Por compatibilidad con versiones anteriores, este método aún devuelve un pequeño subconjunto de sus datos, incluidas las tareas propias de la aplicación llamante y posiblemente algunas otras tareas no sensibles (como Home). Si su aplicación está utilizando este método para recuperar sus propias tareas, utilice android.app.ActivityManager.getAppTasks () en su lugar para recuperar esa información.
Consulte la descripción general de la API de Android L aquí https://developer.android.com/preview/api-overview.html#Behaviors
Para un proyecto reciente en el que trabajé, también necesito detectar cuándo se lanzan ciertas aplicaciones. Toda mi investigación condujo al método getRunningTasks, que está en desuso a partir de Lollipop. Sin embargo, para mis sorpresas, descubrí que algunas de las aplicaciones de bloqueo de aplicaciones aún funcionan en los dispositivos de lollipop, por lo que deben haber encontrado una solución para evitar esto. Así que cavé un poco más profundo. Esto es lo que descubrí:
- En dispositivos pre-L, todavía usan getRunningTasks
- En los dispositivos L, usan getRunningAppProcesses, que devuelve una lista de los procesos que se ejecutan actualmente en los dispositivos. Podrías pensar "bueno, eso no es útil". Cada processInfo tiene una importancia atribuida llamada. Cuando una aplicación se convierte en actividad principal, su importancia processInfo también cambia a IMPORTANCE_FOREGROUND. Por lo tanto, puede filtrar los procesos que no están en primer plano. Desde cada ProcessInfo, también puede solicitar una lista de los paquetes que cargó. Luego puede verificar si la lista contiene el mismo paquete que la aplicación cuando intentan "proteger".
Algunos ejemplos de código para detectar cuándo se inicia la aplicación de calendario predeterminada:
public class DetectCalendarLaunchRunnable implements Runnable {
@Override
public void run() {
String[] activePackages;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
activePackages = getActivePackages();
} else {
activePackages = getActivePackagesCompat();
}
if (activePackages != null) {
for (String activePackage : activePackages) {
if (activePackage.equals("com.google.android.calendar")) {
//Calendar app is launched, do something
}
}
}
mHandler.postDelayed(this, 1000);
}
String[] getActivePackagesCompat() {
final List<ActivityManager.RunningTaskInfo> taskInfo = mActivityManager.getRunningTasks(1);
final ComponentName componentName = taskInfo.get(0).topActivity;
final String[] activePackages = new String[1];
activePackages[0] = componentName.getPackageName();
return activePackages;
}
String[] getActivePackages() {
final Set<String> activePackages = new HashSet<String>();
final List<ActivityManager.RunningAppProcessInfo> processInfos = mActivityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo processInfo : processInfos) {
if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
activePackages.addAll(Arrays.asList(processInfo.pkgList));
}
}
return activePackages.toArray(new String[activePackages.size()]);
}
}
Nota: getRunningAppProcesses también está destinado a la depuración o "creación de una interfaz de usuario de administración de procesos orientada al usuario". No estoy seguro si Google cerrará esta puerta trasera de la misma manera que lo hicieron con getRunningTasks.
Entonces, no, ya no puedes obtener topActivity. Pero con un poco de hack puedes lograr resultados similares.
private String getProcess() throws Exception {
if (Build.VERSION.SDK_INT >= 21) {
return getProcessNew();
} else {
return getProcessOld();
}
}
//API 21 and above
private String getProcessNew() throws Exception {
String topPackageName = null;
UsageStatsManager usage = (UsageStatsManager) context.getSystemService(Constant.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> stats = usage.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - ONE_SECOND * 10, time);
if (stats != null) {
SortedMap<Long, UsageStats> runningTask = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : stats) {
runningTask.put(usageStats.getLastTimeUsed(), usageStats);
}
if (runningTask.isEmpty()) {
return null;
}
topPackageName = runningTask.get(runningTask.lastKey()).getPackageName();
}
return topPackageName;
}
//API below 21
@SuppressWarnings("deprecation")
private String getProcessOld() throws Exception {
String topPackageName = null;
ActivityManager activity = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> runningTask = activity.getRunningTasks(1);
if (runningTask != null) {
RunningTaskInfo taskTop = runningTask.get(0);
ComponentName componentTop = taskTop.topActivity;
topPackageName = componentTop.getPackageName();
}
return topPackageName;
}
//required permissions
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
<uses-permission android:name="android.permission.GET_TASKS"/>