Cannot get foreground activity name in Android Lol

2019-01-10 17:48发布

问题:

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

回答1:

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



回答2:

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


回答3:

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


回答4:

getRunningTasks()

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.



回答5:

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.



回答6:

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



回答7:

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