Show app usage with UsageStatsManager

Lorenzo Quiroli
4 min readDec 23, 2016

--

Android 5.0 Lollipop introduced lots of goodness for us Android developers, but here’s something you might have missed: UsageStatsManager.

Recently I had to build an app manager at work which tracks the usage of the installed apps on the device to advice the user of which he should uninstall. To achieve this goal I had to learn about something new: UsageStatsManager.

What is UsageStatsManager?

UsageStatsManager is a new API introduced in Android 5.0 Lollipop (API Level 21) which allows us to retrieve statistics about the usage of the apps installed on the device.

That’s not everything you can do with UsageStatsManager. I focused on the app usage but you can also get useful data like UsageEvents or ConfigurationStats. The former are events happened on the device, like a configuration change or an app moving to the foreground/background, or even the end of a day, while the latter contains basically just a Configuration object plus various info about when it happened. I won’t deep dive into this though, since the API design is quite similar and once you get how it works for UsageStats, dealing with UsageEvents and ConfigurationStats will be the same.

Getting started with UsageStatsManager: requesting permission

Let’s start by declaring a permission in our Manifest before being able to access the user’s usage data:

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

The reason behind the use of the tools:ignore instruction is the permission: being a system level one, Android Studio will highlight it with a red line… but we know what we are doing, aren’t we?

Your code will still compile fine even if you don’t add this instruction since its main purpose is reminding us that just declaring it won’t be enough, the user will have to grant it from the dedicated settings page.

Because we’re talking about a system-level permission, the check for the PACKAGE_USAGE_STATS permission might be a little different from what you know:

In case this is false, you can might want to provide a shortcut to the related settings screen (which you can find in Settings > Security > Apps with usage access):

startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));

Next, we can finally access our the UsageStatsManager !

UsageStatsManager usageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);

At this point you might notice that Android Studio is giving you a warning: that’s because the constant USAGE_STATS_SERVICE was actually introduced on API 22.

Thanks, Obama

So if you want to use this on API 21, you’ll need to pass the string value, which is “usagestats”. You’ll get another warning in Android Studio, but yeah, about that: ¯\_(ツ)_/¯

Finally: querying for the usage data

Once you handled the permission and the user decided you’re trustworthy, you can retrieve usage stats by calling the method queryUsageStats(int intervalType, long beginTime, long endTime) which will return a list of UsageStats.

I’d advice you to move this call on a worker thread since the queryUsageStats method can take enough time to cause your UI to drop some frames if you don’t move it off the main thread.

Wait, what’s an intervalType? Well, the system collects and aggregates the data over 4 different intervals (defined by a constant int value which is contained in the class UsageStatsManager) and they are:

Keep in mind that 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. Note that even if the time frame you picked lasts five minutes, if you picked INTERVAL_WEEKLY as intervalType you will get all the stats inside that interval.

Not sold with the idea of getting a list with hundreds, maybe thousands of entries? There’s also a utility method to retrieve app usage stats, which is queryAndAggregateUsageStats(long beginTime, long endTime). This will merge for us all the instances of UsageStats retrieved for a package and returns a map with a String (the package name) as key and the merged UsageStats as value.

If you’re wondering why we don’t need to pass an interval type this time, well, that’s because it will always use INTERVAL_BEST, no matter which start and end time values you picked.

queryAndAggregateUsageStats(long beginTime, long endTime) could be a better choice if you just want to get the absolute value of the total foreground time or the last time that app was used, since the merging basically sums the foreground time of the different UsageStats objects and it keeps the most recent lastTimeUsed value.

What does a UsageStats contain?

Inside a UsageStats you’ll be able to find the beginning time and ending time for that stat, the amount of time in foreground during that timespan and the last time it was used. Of course there’s also the package name of the app.

Finally, if you’re on API 23 or higher, you can also use the method isAppInactive(String packageName) in the UsageStatsManager class, which tells us whether an app is currently active or not (according to the official documentation an app is considered inactive if it’s not used for a period of time which can last several hours or days).

I want more code!

You can find a sample I built on GitHub.

Thanks to Roberto Orgiu for proofreading this article.

--

--