Search code examples
javaandroidandroidx

Android: UsageStats returning 0 on getTotalTimeInForeground() for certain apps


I'm trying to fetch the daily screen time of each application that is installed on my phone using the following code from a service.

UsageStatsManager statsManager = (UsageStatsManager)service.getSystemService(Context.USAGE_STATS_SERVICE);

//todayDate is start of the day and today is current time

dailyUsage = statsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, todayDate.toDate().getTime(), today.toDateTime().getMillis());
for(UsageStats stats: dailyUsage){
  Long totalTime = stats.getTotalTimeInForeground();
  String app = stats.getPackageName();
  Log("TotalTimeUsedToday", app + " " + totalTime);
}

I'm getting duplicate apps and some apps show 0 totalTime though sometimes it shows correct screen time.


Solution

  • Since the queryUsageStats works in a weird way, I decided to drop it and use queryEvents instead. Here's the complete function that works like a charm for my use case:

    private Map<String, Long> testUsageStats(long startTime) {
    
        long currTime = System.currentTimeMillis();
        UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
        UsageEvents usageEvents = mUsageStatsManager.queryEvents(startTime, currTime);
    
        Map<String, Long> eventUsage = new HashMap<>();
        Map<String, Long> totalUsage = new HashMap<>();
    
        String lastApp = "xx";
    
        while (usageEvents.hasNextEvent()) {
            UsageEvents.Event currentEvent = new UsageEvents.Event();
            usageEvents.getNextEvent(currentEvent);
    
            String app = currentEvent.getPackageName();
            Long time = currentEvent.getTimeStamp();
    
            if (currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED
                || currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_PAUSED) {
    
                if (currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED) {
                    eventUsage.put(app, time);
                    lastApp = app;
                }
                else {
                    if (eventUsage.containsKey(app))
                        if (totalUsage.containsKey(app))
                            totalUsage.put(app, totalUsage.get(app) + (time - eventUsage.get(app)));
                        else
                            totalUsage.put(app, (time - eventUsage.get(app)));
                    eventUsage.remove(app);
                }
            }
        }
    
        if(eventUsage.containsKey(lastApp))
            if (totalUsage.containsKey(lastApp))
                totalUsage.put(lastApp, totalUsage.get(lastApp) + (System.currentTimeMillis() - eventUsage.get(lastApp)));
            else
                totalUsage.put(lastApp, (System.currentTimeMillis() - eventUsage.get(lastApp)));
    
        for (String key : totalUsage.keySet()) {
            Log("TestTimeUsed", key + " " + totalUsage.get(key));
        }
    
        return totalUsage;
    
    }
    

    This snippet covers the edge case of currently running app. Edge case at start time in which app has been started before the start time can also be handled with a bit of tweaking.