Blog Infos
Author
Published
Topics
,
Published
Using UsageStatsManager to check app usage history
🗒️ Contents
📌 Why not use ‘ActivityManager.getRunningTasks’?
📌 Alternative: Use ‘ActivityManager.getRunningAppProcesses’
📌 The Solution: Using `UsageStatsManager.queryEvents`
Step 1: 🔐 Requesting the Permissions
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.shubham0204.ml.ocmsclient">
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
<application>
...
</application>
</manifest>

Snippet 1: Adding the PACKAGE_USAGE_STATS permission to AndroidManifest.xml

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

, ,

Migrating to Jetpack Compose – an interop love story

Most of you are familiar with Jetpack Compose and its benefits. If you’re able to start anew and create a Compose-only app, you’re on the right track. But this talk might not be for you…
Watch Video

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engineer for Jetpack Compose
Google

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engin ...
Google

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engineer f ...
Google

Jobs

Step 2: 🔑 Checking the status of the permission and requesting it
// The `PACKAGE_USAGE_STATS` permission is a not a runtime permission and hence cannot be
// requested directly using `ActivityCompat.requestPermissions`. All special permissions
// are handled by `AppOpsManager`.
private fun checkUsageStatsPermission() : Boolean {
val appOpsManager = getSystemService(AppCompatActivity.APP_OPS_SERVICE) as AppOpsManager
// `AppOpsManager.checkOpNoThrow` is deprecated from Android Q
val mode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
appOpsManager.unsafeCheckOpNoThrow(
"android:get_usage_stats",
Process.myUid(), packageName
)
}
else {
appOpsManager.checkOpNoThrow(
"android:get_usage_stats",
Process.myUid(), packageName
)
}
return mode == AppOpsManager.MODE_ALLOWED
}

Snippet 2: Checking the status of the PACKAGE_USAGE_STATS permission using AppOpsManager

 

In order to request the PACKAGE_USAGE_STATS permission, we can’t use the ActivityCompat.requestPermissions method or the ActivityResultContracts.RequestPermission() as this is not a runtime permission, as we discussed earlier. Instead, we need to navigate the user to the Settings page where the user enables this permission for the app,

if ( checkUsageStatsPermission() ) {
// Implement further app logic here ...
}
else {
// Navigate the user to the permission settings
Intent( Settings.ACTION_USAGE_ACCESS_SETTINGS ).apply {
startActivity( this )
}
}

Snippet 3: Requesting the PACKAGE_USAGE_STATS permission after checking the status the permission

 

Usage Data Settings as observed in a Android 9 device ( Samsung J7 ).

 

Step 3: 📱Retrieving Usage Events
var foregroundAppPackageName : String? = null
val currentTime = System.currentTimeMillis()
// The `queryEvents` method takes in the `beginTime` and `endTime` to retrieve the usage events.
// In our case, beginTime = currentTime - 10 minutes ( 1000 * 60 * 10 milliseconds )
// and endTime = currentTime
val usageEvents = usageStatsManager.queryEvents( currentTime - (1000*60*10) , currentTime )
val usageEvent = UsageEvents.Event()
while ( usageEvents.hasNextEvent() ) {
usageEvents.getNextEvent( usageEvent )
Log.e( "APP" , "${usageEvent.packageName} ${usageEvent.timeStamp}" )
}

Snippet 4: Requesting the usage events using the `usageStatsManager.queryEvents` method.

 

The output of code snippet 4. The last line in the output above shows the name of the calling package.

Step 4: Filtering user-installed apps ( Optional )
private fun getNonSystemAppsList() : Map<String,String> {
val appInfos = packageManager.getInstalledApplications( PackageManager.GET_META_DATA )
val appInfoMap = HashMap<String,String>()
for ( appInfo in appInfos ) {
if ( appInfo.flags != ApplicationInfo.FLAG_SYSTEM ) {
appInfoMap[ appInfo.packageName ]= packageManager.getApplicationLabel( appInfo ).toString()
}
}
return appInfoMap
}

Snippet 5: Getting a `Map` containing package names and labels of user-installed apps

 

Step 5: Check if user is unlocked ( from Android R )
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val userManager = getSystemService( Context.USER_SERVICE ) as UserManager
if ( userManager.isUserUnlocked ) {
// Access usage history ...
}
}

Snippet 6: Checking if the user is unlocked with UserManager

 

📍 We’re done!

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
This tutorial is the second part of the series. It’ll be focussed on developing…
READ MORE
blog
We recently faced a problem with our application getting updated and reaching slowly to…
READ MORE
blog
A few weeks ago I started with a simple question — how to work…
READ MORE
blog
One of the main functions of a mobile phone was to store contacts information.…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu