Android 如何使用 UsageStatsManager?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26431795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:24:22  来源:igfitidea点击:

How to use UsageStatsManager?

androidusage-statisticsactivity-managerandroid-recentsusagestatsmanager

提问by android developer

Background

背景

Google has deprecated the function "getRecentTasks" of "ActivityManager" class. Now all it does is to get the list of apps that the current app has opened.

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

I've even written a post about it here on StackOverflow, but I noticed it's impossible.

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

The problem

问题

I've made a post about it (here, and another, similar one created by someone else, here) and requested to re-consider it, and Google decided to make a new class, that seem to provide a similar functionality (more like statistics, but might also be useful), but I can't find out how to use it.

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

The class is called "UsageStatsManager", and my guess is that the function "queryUsageStats" does the job.

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

Also, it seems it has a new permission ("android.permission.PACKAGE_USAGE_STATS"), which is a system permission, but it's written that:

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

declaring the permission implies intention to use the API and the user of the device can grant permission through the Settings application.

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

Here'sanother link about this new functionality.

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

What I've found

我发现了什么

I've looked at the code of Android, and noticed that "Context" has USAGE_STATS_SERVICE , which in the JavaDocs say the next thing:

我查看了 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";

The weird thing is that not only it says "status bar", but also the packageName doesn't match (should be "android.app.usage.UsageStatsManager" instead) .

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

I've also added the correct permission:

我还添加了正确的权限:

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

and here's the code I use:

这是我使用的代码:

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

In the emulator itself, I went to "Settings"->"security"->"apps with usage access" , and enabled my app.

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

However, when running the code, all I get is an empty list...

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

The question

问题

How do you use UsageStatsManager?

你怎么用UsageStatsManager

Also, how do you let the user to grant the permission in the easiest way possible? Or is it automatically done, as soon as the app tries to get the needed information?

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

What happens when trying to use this class yet the user hasn't confirmed it yet?

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

How can I make the code return me a real list of apps?

我怎样才能让代码返回一个真正的应用程序列表?

采纳答案by Atish

I think the documentation was just short hand for the Calendar stuff. I don't think it actually works with just 2014; however I can be wrong.

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

In order to access the actually list of UsageStats, you would need to create a Calendar object with the correct month,day, and year. Exactly how MRK said in the other answer. I copied and corrected the errors in MRK's code so anyone who sees it in the future can see it.

为了访问 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());

-Credit MRK; corrected by me (he accidentally just put cal instead of beginCal and endCal)

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

The code for the usage access settings is below. :)

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

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);

回答by Cole Murray

I've created a sample of how to use UsageStats on my Github. Hopefully it can be of help to someone

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

https://github.com/ColeMurray/UsageStatsSample

https://github.com/ColeMurray/UsageStatsSample

回答by MRK

Answering your last question "How can I make the code return me a real list of apps?". queryUsageStats takes begin time and end time in milliseconds, not the value of the year in int.

回答你的最后一个问题“如何让代码返回一个真正的应用程序列表?”。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());

This should return a list of UsageStats for the years 2012 and 2013 (keep in mind the end time is exclusive of the end result time range).

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

回答by Sam Lu

Use UsageStats will get the wrong information when user opens the notification drawer or on a locked screen. You have to use UsageStatsManager.queryEvents() and look for the latest event with MOVE_TO_FOREGROUND event type.

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

回答by justfortherec

There is actually an example app included in AOSP sample code: developers/samples/android/system/AppUsageStatistics/

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

It includes all the bits necessary to use UsageStatsin an app:

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

  1. Declaring the permission in AndroidManifest.xml

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

  2. Show settings to grant permission to access UsageStatsManager

    startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));

  3. Query UsageStatsManagerfor statistics.

    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.YEAR, -1);
    List<UsageStats> queryUsageStats = mUsageStatsManager
            .queryUsageStats(intervalType, cal.getTimeInMillis(),
                    System.currentTimeMillis());
    
  4. Creating a list of apps based on 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

To summarize and apply to your example:

总结并应用于您的示例:

  • You seem to correctly ask for and grant permissions to access usage stats.
  • You correctly get the UsageStatssystem service.
  • However, the time period you query for is way to short: Arguments beginTimeand endTimeare measured in milliseconds since the epoch. Calendarinstances can give you this value with getTimeinMillis(). What you erroneously do is to only give the year numbers (2015and2017if you would run the program today). These values are interpreted as milliseconds since the epoch and thus the interval is only 2 milliseconds long and is some time in 1970.
  • 您似乎正确地请求并授予访问使用情况统计信息的权限。
  • 您正确获得UsageStats系统服务。
  • 但是,您查询的时间段很短:参数beginTimeendTime自纪元以来的毫秒数。Calendar实例可以为您提供此值getTimeinMillis()。你错误地做的是只给一年的数字(20152017如果你运行程序今天)。这些值被解释为自纪元以来的毫秒数,因此间隔只有 2 毫秒长,并且是 1970 年的某个时间。

Instead of the following code snippet that you posted, you should copy the example I posted below:

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

Wrong:

错误的:

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

Correct:

正确的:

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

回答by Msgun

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.

如果您想查看特定时间段的使用情况统计信息,您必须首先计算自 epoch 以来您的时间段开始和结束的时间长度(以毫秒为单位)。(纪元是自 1970 年 1 月 1 日星期四 00:00:00 UTC 以来经过的秒数。)或者,正如我将在以下示例代码中展示的那样,一种简单的方法是从当前时间向后计算(以毫秒为单位)。

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

例如,如果您想要过去 4 天的使用情况统计,您可以使用以下代码:

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.

数字 345600000 是 4 天内的毫秒数。

And for the INTERVAL_TYPEthis articleexplains it well.

对于INTERVAL_TYPE这篇文章解释得很好。

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.

系统收集和聚合 4 个不同时间间隔的数据,它们是:INTERVAL_DAILY、INTERVAL_WEEKLY、INTERVAL_MONTHLY 和 INTERVAL_YEARLY。系统记录是有时间限制的,因此您可以检索最多 7 天的时间间隔,每周最多 4 周,每月最多 6 个月,最终每年最多 2 年的应用程序使用数据.

还有第五个选项要提及:INTERVAL_BEST 将根据您选择的时间跨度选择上述四个之间的最佳拟合间隔。

回答by Abdul Rehman Janjua

you can do like this

你可以这样做

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