26

背景

我的应用程序允许按最近启动的时间对应用程序列表进行排序。

问题

从 Android "L" 开始,函数getRecentTasks将只返回当前应用程序已启动的应用程序列表,如文档中所述:

如果您的应用使用 ActivityManager.getRecentTasks()...

随着在即将发布的版本中引入新的并发文档和活动任务功能(请参阅下面最近屏幕中的并发文档和活动),现在不推荐使用 ActivityManager.getRecentTasks() 方法以改善用户隐私。为了向后兼容,此方法仍然返回其数据的一小部分,包括调用应用程序自己的任务和可能的其他一些非敏感任务(例如 Home)。如果您的应用正在使用此方法来检索自己的任务,请使用 android.app.ActivityManager.getAppTasks() 来检索该信息。

使用 ADT 显示此功能的文档时也是如此(目前在 Internet 上不可用):

此方法已弃用。从 L 开始,第三方应用程序不再可以使用此方法:因为引入以文档为中心的最近消息意味着它可能会将个人信息泄露给调用者。为了向后兼容,它仍将返回其数据的一小部分:至少是调用者自己的任务(尽管请参阅 getAppTasks() 以了解获取该信息的正确支持方式),以及可能已知的其他一些任务,例如 home不要敏感。

我不明白为什么要采取这种行为,因为很容易看到用户拥有哪些应用程序,即使没有任何许可。

问题是,这是我添加的这个功能的一个很大的限制,所以我希望有办法克服这个问题。

我试过的

目前,我只对最近启动了哪些应用程序使用了启发式方法——我得到了正在运行的进程列表。

我也可以使用流程的重要性值,也许还有“importanceReasonComponent”,但这只是所有的启发式和猜测......

问题

有没有办法克服这个限制?有什么我没有想到的解决方法吗?

也许它是可能的根?还是忙箱?

4

4 回答 4

38

要获取当前运行的顶级(前台)包名称,您需要使用 Android Lollipop 中的 Usage Stats API。

但请注意,用户必须在每个应用程序的设置中批准对使用数据的访问。因此,您应该通过启动设置操作直接提示用户设置

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);

要获得顶级包名:

String topPackageName ;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
    UsageStatsManager mUsageStatsManager = (UsageStatsManager)getSystemService("usagestats");                       
    long time = System.currentTimeMillis(); 
    // We get usage stats for the last 10 seconds
    List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*10, time);                                    
    // Sort the stats by the last time used
    if(stats != null) {
        SortedMap<Long,UsageStats> mySortedMap = new TreeMap<Long,UsageStats>();
        for (UsageStats usageStats : stats) {
            mySortedMap.put(usageStats.getLastTimeUsed(),usageStats);
        }                    
        if(!mySortedMap.isEmpty()) {
            topPackageName =  mySortedMap.get(mySortedMap.lastKey()).getPackageName();                                   
        }                                       
    }
}
于 2014-11-12T11:07:03.080 回答
9

如果您使用 UsageStats 获取当前前台包,当用户打开通知抽屉或锁定屏幕时,您将获得错误信息。(在 Android Lollipop 和 Marshmallow 上测试)

您必须使用 UsageStatsManager.queryEvents() 并查找具有 MOVE_TO_FOREGROUND 事件类型的最新事件来确定当前的前台包。

于 2016-04-29T14:53:51.403 回答
2

@user3742392 答案很好,但是使用 TreeMap 查找上次使用的时间有点矫枉过正(特别是如果您想定期检查运行最频繁的应用程序)。

这是编辑后的答案,没有带有简单循环的 TreeMap:

String topPackageName;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService("usagestats");
    long currentTime = System.currentTimeMillis();
    // get usage stats for the last 10 seconds
    List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, currentTime - 1000 * 10, currentTime);
    // search for app with most recent last used time
    if (stats != null) {
        long lastUsedAppTime = 0;
        for (UsageStats usageStats : stats) {
            if (usageStats.getLastTimeUsed() > lastUsedAppTime) {
                topPackageName = usageStats.getPackageName();
                lastUsedAppTime = usageStats.getLastTimeUsed();
            }
        }
    }
}
于 2015-11-06T14:27:52.133 回答
1

Lollipop 已弃用该方法;但是有一个新的 API 允许您查看应用程序的使用情况。由于安全问题,该方法已被弃用。:\

UsageStatsManager 有一些有用的方法来查看时间间隔之间的活动。希望这足以满足您的需求!

https://developer.android.com/reference/android/app/usage/package-summary.html

于 2014-10-27T01:09:12.693 回答