Android 5.0版本中无法获取前台活动名称

21

我使用以下代码将前台应用程序的活动名称存储在变量foregroundTaskPackageName中。它适用于Android 4.1到4.4之间的所有操作系统版本,但在Android 5.0 Lollipop上无法正常工作。

有人可以帮忙解释一下Lollipop中发生了什么变化吗?在Lollipop中,我得到的foregroundTaskPackageName文本只是“Launcher3”。我正在使用Genymotion模拟器。

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

请问您是否可以使用最新的Android L UsageStatsManager检索topActivity。如果可以,请告诉我如何操作。同时,如果有示例代码将会非常有用。谢谢。 - user3144836
@user3144836:你能找到获取TopActivity的方法吗? - venkat
@venkat :不,我还没有想到在Android 5.0棒棒糖中如何做到这一点。 - user3144836
在这个帖子中已经回答了同样的问题 https://dev59.com/LnI95IYBdhLWcg3www2Y#30778294请看一下。 - Suman
我解决了这个问题,请看我的答案: https://dev59.com/4pHea4cB1Zd3GeqPkRbk#36086106 - johnny_kb
7个回答

29

这对我在Lollipop(21)上有效:

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

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

    Log.i("current_app",tasks.get(0).processName);

有没有一种方法可以使用这种方法获取顶部活动? - venkat
因为我希望能够在应用程序中获取某个具体活动的通知。 - venkat
@venekat 抱歉,这只能获取当前正在运行的应用程序,而不能获取活动。 - Mert
1
请注意,API中不保证此行为。请参阅有关排序未指定的说明。即使现在可以工作,此行为也可能在将来发生变化。http://developer.android.com/reference/android/app/ActivityManager.html#getRunningAppProcesses() - J Wang
10
这只会返回您自己的包名,已在Motorolla MotoX上进行测试。 - Farhad
@FarhadFaghihi 最后一行代码返回当前正在运行的进程。在您的情况下,如果您的当前应用程序是您的包,则为您自己的包名称。tasks对象包含所有正在运行的进程,请查看tasks对象,您将看到所有正在运行的进程。 - Mert

9
你需要使用新的UsageStatsManager并调用其queryUsageStats方法来获取启动活动的历史记录。 请注意,用户需要在设备设置中的安全性-应用程序中提供使用情况统计访问权限。
链接: UsageStatsManager文档 queryUsageStats方法文档

8

您可以使用以下代码获取当前前台活动的包名。

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

将这些权限添加到清单文件中(第一个是针对API 21以下版本,第二个是针对API 21及以上版本)。

<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />

你在你的应用程序中运行了这段代码吗?因为我找不到UsageStatsManager。你能分享你的Java文件或代码吗? - Nitish Patel
1
@nitishpatel UsageStatsManager 只存在于 API 21 及以上的版本。 - Vicky Chijwani
1
这对于前台包名称有效,但活动类名称呢? - user1118764
@user1118764 你找到获取activity类名的方法了吗?请告诉我。 - KK_07k11A0585

4
根据getRunningTasks()文档:

此方法已在API 21中弃用。从LOLLIPOP开始,第三方应用程序将不再可用此方法:文档为中心的最近活动清单的引入可能会向调用者泄露个人信息。为了向后兼容,它仍将返回其数据的一小部分:至少包括调用者自己的任务,以及可能一些其他任务,例如主屏幕,这些任务已知不敏感。


2
我创建了一个类,使用/system/bin/toolbox命令来识别进程,然后识别可见应用程序。需要添加识别没有UI的系统应用程序和android启动器。 ProcessManager.java

2

一种可用但不是最佳的方法是使用辅助功能。

在AndroidManifest xml文件中声明一个辅助功能服务。

<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文件

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

当窗口状态改变时,存储活动名称

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

    }

}

缺点是需要让用户在设置中启用您的辅助功能服务。

0

试试这个

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接