59

背景

Google 已弃用getRecentTasks“ActivityManager”类的“”功能。现在它所做的就是获取当前应用程序已打开的应用程序列表。

我什至在 StackOverflow 上写过一篇关于它的文章,但我注意到这是不可能的。

问题

我已经发表了一篇关于它的帖子(这里和另一个由其他人创建的类似的帖子,这里)并要求重新考虑它,谷歌决定创建一个新类,它似乎提供了类似的功能(更像统计,但也可能有用),但我不知道如何使用它。

该类被称为“ UsageStatsManager”,我的猜测是函数“ queryUsageStats”完成了这项工作。

此外,它似乎有一个新权限(“ android.permission.PACKAGE_USAGE_STATS”),这是一个系统权限,但它写的是:

声明权限意味着使用 API 的意图,并且设备的用户可以通过设置应用程序授予权限。

这是有关此新功能的另一个链接。

我发现了什么

我查看了 Android 的代码,并注意到“上下文”有 USAGE_STATS_SERVICE ,在 JavaDocs 中说下一件事:

/**
 * Use with {@link #getSystemService} to retrieve a {@link
 * android.app.UsageStatsManager} for interacting with the status bar.
 *
 * @see #getSystemService
 * @see android.app.UsageStatsManager
 * @hide
 */
public static final String USAGE_STATS_SERVICE = "usagestats";

奇怪的是,它不仅说“ status bar”,而且 packageName 也不匹配(应该是“ android.app.usage.UsageStatsManager”)。

我还添加了正确的权限:

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

这是我使用的代码:

  final UsageStatsManager usageStatsManager=(UsageStatsManager)context.getSystemService("usagestats");// Context.USAGE_STATS_SERVICE);
  final int currentYear=Calendar.getInstance().get(Calendar.YEAR);
  final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,currentYear-2,currentYear);

在模拟器本身中,我去了 " Settings"->"security"->"apps with usage access" ,并启用了我的应用程序。

但是,在运行代码时,我得到的只是一个空列表......

问题

你怎么用UsageStatsManager

另外,您如何让用户以最简单的方式授予权限?还是在应用程序尝试获取所需信息时自动完成?

尝试使用此类但用户尚未确认时会发生什么?

如何让代码返回给我一个真实的应用列表?

4

7 回答 7

32

我认为文档只是日历内容的简写。我认为它实际上不适用于 2014 年。但是我可能是错的。

为了访问 UsageStats 的实际列表,您需要创建一个具有正确月、日和年的 Calendar 对象。MRK 在另一个答案中是怎么说的。我复制并更正了 MRK 代码中的错误,以便将来看到它的任何人都可以看到它。

Calendar beginCal = Calendar.getInstance();
beginCal.set(Calendar.DATE, 1);
beginCal.set(Calendar.MONTH, 0);
beginCal.set(Calendar.YEAR, 2012);

Calendar endCal = Calendar.getInstance();
endCal.set(Calendar.DATE, 1);
endCal.set(Calendar.MONTH, 0);
endCal.set(Calendar.YEAR, 2014);

final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, beginCal.getTimeInMillis(), endCal.getTimeInMillis());

- 信用 MRK;由我纠正(他不小心放了 cal 而不是 beginCal 和 endCal)

使用访问设置的代码如下。:)

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
于 2014-10-29T04:01:24.780 回答
27

我已经在我的 Github 上创建了一个如何使用 UsageStats 的示例。希望它可以对某人有所帮助

https://github.com/ColeMurray/UsageStatsSample

于 2015-03-02T21:27:48.747 回答
9

回答您的最后一个问题“如何使代码返回给我一个真实的应用程序列表?”。queryUsageStats 以毫秒为单位获取开始时间和结束时间,而不是 int 中的年份值。

Calendar beginCal = Calendar.getInstance();
beginCal.set(Calendar.DATE, 1);
beginCal.set(Calendar.MONTH, 0);
beginCal.set(Calendar.YEAR, 2012);

Calendar endCal = Calendar.getInstance();
endCal.set(Calendar.DATE, 1);
endCal.set(Calendar.MONTH, 0);
endCal.set(Calendar.YEAR, 2014);

final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, beginCal.getTimeInMillis(), endCal.getTimeInMillis());

这应该返回 2012 年和 2013 年的 UsageStats 列表(请记住,结束时间不包括最终结果时间范围)。

于 2014-10-28T08:05:08.610 回答
9

AOSP 示例代码中实际上包含一个示例应用程序developers/samples/android/system/AppUsageStatistics/

它包括UsageStats在应用程序中使用所需的所有位:

  1. 声明权限AndroidManifest.xml

    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>

  2. 显示设置以授予访问权限UsageStatsManager

    startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));

  3. 查询UsageStatsManager统计。

    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.YEAR, -1);
    List<UsageStats> queryUsageStats = mUsageStatsManager
            .queryUsageStats(intervalType, cal.getTimeInMillis(),
                    System.currentTimeMillis());
    
  4. 创建基于应用程序的列表UsageStats

总结并应用于您的示例:

  • 您似乎正确地请求并授予访问使用情况统计信息的权限。
  • 您正确获得了UsageStats系统服务。
  • 但是,您查询的时间段太短:参数beginTimeendTime自纪元以来以毫秒为单位测量。Calendar实例可以给你这个值getTimeinMillis()。您错误地做的是只给出年份数字(2015如果2017您今天运行该程序)。这些值被解释为自纪元以来的毫秒数,因此间隔只有 2 毫秒长,是 1970 年的某个时间。

您应该复制我在下面发布的示例,而不是您发布的以下代码片段:

错误的:

final int currentYear=Calendar.getInstance().get(Calendar.YEAR);
final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,currentYear-2,currentYear);

正确的:

final long currentTime = System.currentTimeMillis(); // Get current time in milliseconds

final Calendar cal = Calendar.getInstance();
cal.add(Calendar.YEAR, -2); // Set year to beginning of desired period.
final long beginTime = cal.getTimeInMillis(); // Get begin time in milliseconds

final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, beginTime, currentTime);
于 2017-03-02T16:12:30.757 回答
7

当用户打开通知抽屉或锁定屏幕时,使用 UsageStats 会得到错误信息。您必须使用 UsageStatsManager.queryEvents() 并使用 MOVE_TO_FOREGROUND 事件类型查找最新事件。

于 2016-04-29T14:49:59.857 回答
1

If you want to see usage statistics of a specific time period, you have to first calculate the length of time in milliseconds of the start and end of your time period since the epoch. (epoch is the number of seconds that have elapsed since 00:00:00 UTC, Thursday 1, 1970.) Or, as I will show in the following sample code, an easy way is to calculate backwards from the current time in milliseconds.

For example, if you want a usage statistic of the past 4 days, you can use the following code:

UsageStatsManager mUsageStatsManager = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE);    
List<UsageStats> queryUsageStats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
                    (System.currentTimeMillis() - 345600000), System.currentTimeMillis());

The number 345600000 is the number of milliseconds in 4 days.

And for the INTERVAL_TYPE this article explains it well.

The system collects and aggregates the data over 4 different intervals and they are: INTERVAL_DAILY, INTERVAL_WEEKLY, INTERVAL_MONTHLY and INTERVAL_YEARLY. The system records are limited in time, so you’ll be able to retrieve app usage data for up to 7 days for interval daily, up to 4 weeks for interval weekly, up to 6 months for monthly and finally up to 2 years for yearly.

There’s a fifth option to mention: INTERVAL_BEST will choose the best fitting interval between the four above based on the timespan you’ve chosen.

于 2018-08-19T20:09:59.867 回答
0

你可以这样做

//noinspection ResourceType
final UsageStatsManager usageStatsManager=(UsageStatsManager)context.getSystemService("usagestats");// Context.USAGE_STATS_SERVICE);
final int currentYear=Calendar.getInstance().get(Calendar.YEAR);
final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,currentYear-2,currentYear);
于 2016-05-17T13:40:51.777 回答