How can I retrieve screen time for all apps used in the past 24 hours using UsageStatsManager in an Android app developed in Kotlin?

292 Views Asked by At

I'm working on an Android app in Kotlin, and I need to track and display the screen time for all apps that have been used in the past 24 hours. I understand that I can use the UsageStatsManager for this purpose. Also, I have given the neccessary permission to the app.

I've already added the necessary permissions in my AndroidManifest.xml and implemented the permission request logic. However, I'm having some trouble querying the usage stats and extracting the screen time for each app.

Sometimes, I am getting two instances of one app, and in one instance, the time increases while in the second instance, the time does not increase. Additionally, I'm writing code to get the app icon and app name, but my application crashes.

Could someone provide a code example or a step-by-step guide on how to correctly use the UsageStatsManager to get the screen time of all apps used in the past 24 hours and handle multiple instances of the same app? I would also appreciate guidance on retrieving app icons and names without causing application crashes.

<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
private fun getAppUsageStats(context: Context): List<UsageStats> {
        val usageStatsManager =
            context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
        val endTime = System.currentTimeMillis()

        // Set the start time to a reasonable value (e.g., 24 hours ago or as needed)
        val startTime = endTime - (24 * 60 * 60 * 1000) // 24 hours ago

        // Query app usage statistics for the specified interval

        // Return the list of app usage statistics
        return usageStatsManager.queryUsageStats(
            UsageStatsManager.INTERVAL_DAILY, startTime, endTime
        )
    }
private fun updateUsageStats() {
        val usageStatsList = getAppUsageStats(this)
        val stringBuilder = StringBuilder()

        for (usageStats in usageStatsList) {
            val packageName = usageStats.packageName
            val totalUsageTime = usageStats.totalTimeInForeground / 1000 // in seconds
            if(totalUsageTime == 0L) continue
            stringBuilder.append("$packageName : $totalUsageTime secs\n\n")
        }
        binding.textView.text = stringBuilder.toString()
    }

enter image description here

1

There are 1 best solutions below

8
Hezy Ziv On

The UsageStats object is immutable, so you can't directly modify, create a data class

data class AggregatedUsageStats(
    val packageName: String,
    var totalTimeInForeground: Long
)

private fun getAppUsageStats(context: Context): Map<String, AggregatedUsageStats> {
    val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
    val endTime = System.currentTimeMillis()
    val startTime = endTime - (24 * 60 * 60 * 1000) // 24 hours ago

    val usageStatsList = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, startTime, endTime)

    // Aggregate usage stats by package name
    val aggregatedStats = mutableMapOf<String, AggregatedUsageStats>()
    for (usageStats in usageStatsList) {
        val existingStats = aggregatedStats[usageStats.packageName]
        if (existingStats == null) {
            aggregatedStats[usageStats.packageName] = AggregatedUsageStats(usageStats.packageName, usageStats.totalTimeInForeground)
        } else {
            existingStats.totalTimeInForeground += usageStats.totalTimeInForeground
        }
    }

    return aggregatedStats
}

private fun updateUsageStats() {
    val usageStatsMap = getAppUsageStats(this)
    val packageManager = packageManager
    val stringBuilder = StringBuilder()

    for ((packageName, aggregatedStats) in usageStatsMap) {
        val totalUsageTime = aggregatedStats.totalTimeInForeground / 1000 // in seconds
        if (totalUsageTime == 0L) continue

        // Get app name and icon
        val appInfo = try {
            packageManager.getApplicationInfo(packageName, 0)
        } catch (e: PackageManager.NameNotFoundException) {
            continue
        }
        val appName = packageManager.getApplicationLabel(appInfo).toString()
        val appIcon = packageManager.getApplicationIcon(appInfo)

        // For demonstration purposes, we're just appending the app name to the string.
        // You can use the appIcon drawable as needed in your UI.
        stringBuilder.append("$appName : $totalUsageTime secs\n\n")
    }

    binding.textView.text = stringBuilder.toString()
}