Search code examples
androidreact-nativekotlinmobile

React Native module: usageStatsManager always returns an empty list


I'm trying to use native api. I have the following code to get the 5 most used apps. It's a Native Android module with TypeScript because I can't call APIs with React Native:

fun getUsageData(startTime: Double, endTime: Double, successCallback: Callback) {

    val usageStatsManager = reactApplicationContext.getSystemService(Context.USAGE_STATS_SERVICE) as 
    
    // Query usage stats
    val usageStatsList = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, startTime.toLong(), endTime.toLong())
        
    // Sort usage stats by total time in foreground
    usageStatsList.sortByDescending { it.totalTimeInForeground }

    // Extract package names of top 5 used apps
    val topApps: WritableArray = WritableNativeArray()
    for (i in 0 until minOf(5, usageStatsList.size)) {
        val packageName = usageStatsList[i].packageName
        topApps.pushString(packageName)
    }

    // // Pass the top apps list back to React Native
    successCallback.invoke(topApps)

}

But my list is always empty in Typescript and I don't know why:
LOG Top 5 used apps: []

And this is my TypeScript code:

const getUsageData = () => {

    const startTime = new Date().getTime() - (7 * 24 * 60 * 60 * 1000);
    const endTime = new Date().getTime();

    UsageStatsModule.getUsageData(Number(startTime), Number(endTime), (topApps : any) => {
        console.log('Top 5 used apps:', topApps);
    });
  
};

I don't know how to start for debug, because I have no error and I didn't practice mobile development.

Edit :

I made a few changes to get more information but it wasn't conclusive:

In the manifest.xml :

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

and in the module file :

    @ReactMethod
fun getUsageData(startTime: Double, endTime: Double, successCallback: Callback) {

    try {

        val usageStatsManager: UsageStatsManager = this.reactApplicationContext.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
        
        val cal: Calendar = Calendar.getInstance()
        cal.add(Calendar.DAY_OF_MONTH, -1)

        // Query usage stats
        val usageStatsList = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, cal.timeInMillis, System.currentTimeMillis())
            ?: throw SecurityException("Permission denied or usage stats not available")

        // Sort usage stats by total time in foreground
        usageStatsList.sortByDescending { it.totalTimeInForeground }

        Log.d("a", "a : " + usageStatsList.size)

        // Extract package names of top 5 used apps
        val topApps: WritableArray = WritableNativeArray()

        for(i in 0..usageStatsList.size - 1) {
            val packageName = usageStatsList[i].packageName
            topApps.pushString(packageName)
        }

        // Pass the top apps list back to React Native
        successCallback.invoke(topApps)

    } catch (e: Exception) {
        // Handle exceptions
        e.printStackTrace()
        // Notify React Native about the error
        // You might want to handle this differently based on your app's requirements
        successCallback.invoke(WritableNativeArray().apply {
            pushString("Error: ${e.message}")
        })
    }

}

Edit :

PLease, anyone have an idee ? I m still stuck on this !


Solution

  • I had the same issue. Declaring the permission in the manifest isn't enough in this case (view the guidelines https://developer.android.com/training/permissions/requesting-special). The user needs to grant permission through the Settings app, which you launch with your activity context:

    Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS, Uri.fromParts("package", packageName, null)).also {
         ContextCompat.startActivity(context, it, null)
    }