What app is running right now?!?!?

What app is running right now?!?!?

If you have ever run into the scenario where you need access to the currently running application on your Android device you know that there is always a grey area on how to go about retrieving this information. There is the now deprecated way of grabbing the running tasks from ActivityManager. What has replaced the usage statistics that once used to be managed and controlled by ActivityManager, is now migrated and confined to UsageStatsManager; and has provided us a more more granular and explicity querying system for what we are looking for without the need to do any crazy looping or unneccessary array generation to pull off one entry.

The old (deprecated) way

In the ActivityManager method the GET_TASKS permission is required to be defined in the AndroidManifest (as well as granted by the user on Android 6.0 (API 23+) - but this is deprecated as of API 21 so surely there are better ways right?).

The new way

Querying usage stats via UsageStatsManager (API 22+) is much more granular and you are able to request exactly what periods of time you are interested in. In our case we are only interested in a delta between a short period of time ago until now. I have found the best delta is around 5-10s to cover any asynchronous operations occuring in the service to settle.

Use of the UsageStatsManager requires user permission granting to android.permission.PACKAGE_USAGE_STATS through the Settings application. An intent can be used to launch the user to allow them to grant this permission relatively easily (Hint: Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))

The Reactive Way!

This code used to have live solely in a Service initialized and registered by the application - but that was until the addition of the Lifecycle-Aware components and LiveData now available in Android Jetpack!

LiveData, is observable by nature so we can use that to our advantage and allow us to notify the observers of changes in the data set (in this case the currently running foreground app).

To do so we simply subclass LiveData, with a type definition of UsageStats:

and implement the abstract methods (onActive and onInactive).

Our final result ends up looking something like this:

In order to create the observing fashion of our implementation a neat coroutine called a Channel is used with an increment of 1000 ms (or 1s). This allows us to pick up each app transition to the foreground and alert our observers of each change as they requested. We are also preventing against unwanted quick transitions between apps with our "at least 2" events in a row before triggering a change.

The client side of things

So how do I use this neat observing way of getting the foreground app, especially since a Service isn't a LifecycleOwner?

Simple, you use a Lifecycle-backed Service 😜 Had to do it.

You implement it like every other LiveData element and let the lifecycle components clean up your observer during teardown, with one small catch - being that it is a LiveData (LD) using a Channel you will need to inform the LD to cancel the Channel. To do so simply setup a Observer instance and pass it to observe like you would as an anonymous instance.

In this article we've covered two ways of querying the platform for the currently running, foregrounded application on your or your users Android device - one using ActivityManager which is deprecated as of API 21 (Lollipop), and the replacement using UsageStatsManager available on API 22+ (Nougat). The granularity that UsageStatsManager provides is a huge improvement to the platform, not only for this task, but for the other APIs that it offers as well. This LiveData object will become one of many in a subset that I am creating a library for so keep an ear out for more. If you have any thoughts or questions that you’d like to share, then please do reach out!

This was my first blog post so I hope you enjoyed it!