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
How to use UsageStatsManager?
提问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 的示例。希望它可以对某人有所帮助
回答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 UsageStats
in an app:
它包括UsageStats
在应用程序中使用所需的所有位:
Declaring the permission in
AndroidManifest.xml
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
Show settings to grant permission to access
UsageStatsManager
startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
Query
UsageStatsManager
for statistics.Calendar cal = Calendar.getInstance(); cal.add(Calendar.YEAR, -1); List<UsageStats> queryUsageStats = mUsageStatsManager .queryUsageStats(intervalType, cal.getTimeInMillis(), System.currentTimeMillis());
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
Calendar cal = Calendar.getInstance(); cal.add(Calendar.YEAR, -1); List<UsageStats> queryUsageStats = mUsageStatsManager .queryUsageStats(intervalType, cal.getTimeInMillis(), System.currentTimeMillis());
To summarize and apply to your example:
总结并应用于您的示例:
- You seem to correctly ask for and grant permissions to access usage stats.
- You correctly get the
UsageStats
system service. - However, the time period you query for is way to short: Arguments
beginTime
andendTime
are measured in milliseconds since the epoch.Calendar
instances can give you this value withgetTimeinMillis()
. What you erroneously do is to only give the year numbers (2015
and2017
if 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
系统服务。 - 但是,您查询的时间段很短:参数
beginTime
和endTime
自纪元以来的毫秒数。Calendar
实例可以为您提供此值getTimeinMillis()
。你错误地做的是只给一年的数字(2015
和2017
如果你运行程序今天)。这些值被解释为自纪元以来的毫秒数,因此间隔只有 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_TYPE
this 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);