21

I use the following code to get the activity name of the foreground app in the variable foregroundTaskPackageName. It works on all OS versions between 4.1 to 4.4, but does not work in Android 5.0 Lollipop.

Can anyone help with what has changed in 5.0 Lollipop? In Lollipop - the text I get for foregroundTaskPackageName is just 'Launcher3'. I am using the Genymotion Emulator.

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0); // get
                                                                        // list
                                                                        // of
                                                                        // running
                                                                        // tasks
String foregroundTaskAppName = null;
String foregroundTaskPackageName = foregroundTaskInfo.topActivity
                .getPackageName();
user1406716
  • 9,565
  • 22
  • 96
  • 151
  • I was wondering if you were able to retrieve the topActivity with the new UsageStatsManager for Android L. If yes please let me know how. A sample code would be useful also. Thanks. – user3144836 Dec 26 '14 at 06:28
  • @user3144836 : are you able to find the way to get TopActivity? – venkat Feb 21 '15 at 03:21
  • @venkat : Nope. Haven't figured how to do that yet in Android 5.0 lollipop – user3144836 Feb 22 '15 at 03:54
  • Answered the same in this thread https://stackoverflow.com/questions/2166961/determining-the-current-foreground-application-from-a-background-task-or-service/30778294#30778294 Please have a look. – Suman Jun 11 '15 at 10:31
  • I solved this problem; see my answer here: http://stackoverflow.com/a/36086106/2217336 – johnny_kb Mar 18 '16 at 13:56

7 Answers7

29

This works for me on Lollipop (21):

    ActivityManager manager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);

    List<ActivityManager.RunningAppProcessInfo> tasks = manager.getRunningAppProcesses();

    Log.i("current_app",tasks.get(0).processName);
Mert
  • 1,333
  • 1
  • 12
  • 15
  • Is there a way to get the top activity using this approach? – venkat Feb 21 '15 at 03:18
  • Because i wish to get notified for an exact activity from an application. – venkat Feb 21 '15 at 03:26
  • @venekat sry but this only gets the current running application and not the activity – Mert Feb 21 '15 at 08:21
  • 1
    FYI This behavior is not guaranteed in the API. See the note about the ordering being unspecified. Even if it works now, this behavior could break in the future. http://developer.android.com/reference/android/app/ActivityManager.html#getRunningAppProcesses() – J Wang Jul 07 '15 at 20:46
  • 10
    This only returns your own packagename, tested on Motorolla MotoX – Farhad Oct 28 '15 at 05:23
  • @FarhadFaghihi the last Code line returns the current running process. In your case your own package name if your current Application is your package. the tasks object contains all running processes look into the tasks object and you will see all running processes – Mert Oct 28 '15 at 08:23
9

You need to use the new UsageStatsManager and call its queryUsageStats method to get the history of activities launched. Please note that the user will be required to provide access to usage stat on the device settings at Security->Apps with usage access.

Links:

UsageStatsManager documentation

queryUsageStats method documentation

Muzikant
  • 8,070
  • 5
  • 54
  • 88
8

you can use below code and get the current foreground activity package name.

 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        // intentionally using string value as Context.USAGE_STATS_SERVICE was
        // strangely only added in API 22 (LOLLIPOP_MR1)
        @SuppressWarnings("WrongConstant")
        UsageStatsManager usm = (UsageStatsManager) getSystemService("usagestats");
        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) getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> tasks = am
                        .getRunningAppProcesses();
                currentApp = tasks.get(0).processName;
    }

Add these permissions in to Manifest file (first one is for < API 21, second one for >= API 21).

<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
Vicky Chijwani
  • 10,191
  • 6
  • 56
  • 79
Vishal Butani
  • 356
  • 4
  • 12
4

As per getRunningTasks() docs:

This method was deprecated in API level 21. As of LOLLIPOP, this method is no longer available to third party applications: the introduction of document-centric recents means it can leak person information to the caller. For backwards compatibility, it will still return a small subset of its data: at least the caller's own tasks, and possibly some other tasks such as home that are known to not be sensitive.

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
2

an available but not best way is to use accessibility.

Declare an accessibility service in AndroidManifest xml file

<service
            android:name=".MyAccessibilityService"
            android:label="@string/accessibility_service_label"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>

            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibility_service_config" />
        </service>

accessibility_service_config.xml file

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_desc"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFlags="flagDefault|flagIncludeNotImportantViews"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
/>

store the activity name when window state changed

public class MyAccessibilityService extends AccessibilityService{
    public static String sActivityName;
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        // TODO Auto-generated method stub
        if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED){
            Log.d("activitytest", "onAccessibilityEvent with window state changed");
            sActivityName = event.getClassName().toString();
        }
    }

    @Override
    public void onInterrupt() {
        // TODO Auto-generated method stub

    }

}

The disadvantage is that you need to let users enable your accessibility service in Settings.

gonglong
  • 582
  • 7
  • 14
2

i have created a class that uses /system/bin/toolbox command to identify processes and then identifies visible application. Need to add identifies system apps with no UI and android launchers.

ProcessManager.java

Rukmal Dias
  • 3,242
  • 1
  • 34
  • 28
0

Try this

public static boolean isForeground(Context context) {
    ActivityManager manager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> tasks = manager.getRunningAppProcesses();
    if(tasks.isEmpty())
        return false;

    for (ActivityManager.RunningAppProcessInfo task : tasks) {
        if(context.getPackageName().equalsIgnoreCase(task.processName)){
            return task.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
        }
    }
    return false;
}