Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get (real) foreground process using activityManager.getRunningAppProcesses()

I am trying to determine the currently visible application for the user. To do so, I use the activityManager.getRunningAppProcesses() method.

I know that the method is not supported as off Android 5.1.1 - this is ok.

In the beginning it worked like charm, I am iterating through the list of RunningAppProcessInfos and check for the importance.

tl;dr What is the correct method to get current foreground process and prevent false postives? How is the order of the list done - the API says it is not specified. Is there a way to order them correctly?

What I have done:

Unfortunately the list returned by the ActivityManager is different on every device. Some devices return multiple infos with the importance 100 (which is FOREGROUND), even if the process is currently not visible.

This caused the problem that I had a lot of false positives. For example, I tested it with facebook and created a toast, every time facebook is in foreground. I switched to Home, so my launcher should have been the foreground process. It was for like 10 seconds, after that, facebook appeared with importance FOREGROUND in the list again (it was not open nor visible) and I got a false positive.

I recognized that some devices order the list by the recent process on top. So I decided to try the following approach:

ActivityManager.RunningAppProcessInfo appProcess = appProcesses.get(0);
        final String processName = appProcess.processName;
        final String packageName = removeProcessSuffix(processName);
        if (appProcess.importance == FOREGROUND || appProcess.importance == VISIBLE){
            //do something, like the toast
        }

With appProcesses.get(0); I only examine the first element and the bug was gone. No false positives anymore.

But, now on some devices I do not get the foreground process at all anymore. Because they do not order the list in any way. For example some 4.2 Sony smartphones are some of the candidates. I get the list, but the really currently visible process is at index 11 or so.

I have no clue what to do, to get the current foreground process, without false positives.

What is the correct method to get current foreground process and prevent false postives? How is the order of the list done - the API says it is not specified. Is there a way to order them correctly?

Thanks!

like image 209
JacksOnF1re Avatar asked Dec 10 '15 17:12

JacksOnF1re


1 Answers

What is the correct method to get current foreground process and prevent false positives?

UsageStatsManager is the only official API to get the current running app (see #50).

Using getRunningTasks(int maxNum), getRunningAppProcesses() or AccessibilityService to get the foreground app has never been reliable. The documentation for the first two methods has the following warning: Note: this method is only intended for debugging


Below is an example for getting the top app using UsageStatsManager:

Calendar endCal = Calendar.getInstance();
Calendar beginCal = Calendar.getInstance();
beginCal.add(Calendar.MINUTE, -30);
UsageStatsManager manager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
List<UsageStats> stats =  manager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,  
    beginCal.getTimeInMillis(), endCal.getTimeInMillis());
Collections.sort(stats, new Comparator<UsageStats>() {

  @Override public int compare(UsageStats lhs, UsageStats rhs) {
    long time1 = lhs.getLastTimeUsed();
    long time2 = rhs.getLastTimeUsed();
    if (time1 > time2) {
      return -1;
    } else if (time1 < time2) {
      return 1;
    }
    return 0;
  }
});
// The first "UsageStats" in the list will be the top application.
// If the list is empty you will need to ask for permissions to use UsageStatsManager
// To request permission:
// startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));

I know this isn't the answer you are hoping for. Apps like CM Security and AppLock use UsageStatsManager on Android 5.1.1+. Due to SeLinux, it is impossible to get the foreground app using getRunningTasks(int maxNum) or getRunningAppProcesses().

like image 104
Jared Rummler Avatar answered Sep 21 '22 09:09

Jared Rummler