getRunningTasks doesn't work in Android L

Ligen Yao picture Ligen Yao · Jul 8, 2014 · Viewed 44.1k times · Source

In Android L, Google has disabled getRunningTasks. Now it can only return own apps task and the home launcher. I can no longer get other apps tasks. Our app needs that method to determine current top app. Any one has another method to do this?

I have searched in Google, no more topics about this except this: https://code.google.com/p/android-developer-preview/issues/detail?id=29

Answer

sunxin8086 picture sunxin8086 · Nov 26, 2014

For a recent project that I worked on, I also need to detect when certain applications are launched. All my research lead to the getRunningTasks method, which is deprecated starting from Lollipop. However, to my surprises, I discovered that some of the app lock apps still work on lollipop devices, so they must have come up with a solution to get around this. So I dug a little deeper. Here is what I found out:

    1. On pre-L devices, they still use getRunningTasks
    1. On L devices, they use getRunningAppProcesses, which returns a list of processes currently running on the devices. You might think "well, that is not useful". Each processInfo has a attributed called importance. When an app becomes top activity, its processInfo importance also changes to IMPORTANCE_FOREGROUND. So you can filter out those processes that are not in foreground. From a each ProcessInfo, you can also ask a list of packages it loaded. You can then check if the list contains the same package that the app when are trying "protected".

Some sample code to detect when the default calendar app is launched:

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()]);
}
}

Note: getRunningAppProcesses is also intended for debugging or "building a user-facing process management UI". Not sure if google will close this backdoor the similar way they did to getRunningTasks.

So no, you can't get the topActivity anymore. But with a little bit hack you can achieve similar result.