From a39c3cfebf7e630277cf7dcd7f7978414b4b680f Mon Sep 17 00:00:00 2001 From: Muntashir Al-Islam Date: Sun, 22 Dec 2024 17:26:33 -0800 Subject: [PATCH] [Usage] Fix detecting device shutdowns DEVICE_SHUTDOWN events set android as the default package which caused the Android System package to be displayed in the App Usage page with unusual screen time. Signed-off-by: Muntashir Al-Islam --- .../usage/AppUsageStatsManager.java | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/usage/AppUsageStatsManager.java b/app/src/main/java/io/github/muntashirakon/AppManager/usage/AppUsageStatsManager.java index 5409a5cec98..af43719e940 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/usage/AppUsageStatsManager.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/usage/AppUsageStatsManager.java @@ -67,7 +67,7 @@ public class AppUsageStatsManager { public static final class DataUsage extends Pair implements Parcelable, Comparable { public static final DataUsage EMPTY = new DataUsage(0, 0); - public static DataUsage fromDataUsage(DataUsage ...dataUsages) { + public static DataUsage fromDataUsage(DataUsage... dataUsages) { if (dataUsages == null) { return EMPTY; } @@ -211,14 +211,22 @@ public PackageUsageInfo getUsageStatsForPackage(@NonNull String packageName, PackageUsageInfo packageUsageInfo = new PackageUsageInfo(mContext, packageName, userId, applicationInfo); PerPackageUsageInternal usage = new PerPackageUsageInternal(packageName); List events = UsageStatsManagerCompat.queryEventsSorted(range.getStartTime(), range.getEndTime(), userId, USUAL_ACTIVITY_EVENTS); + long lastShutdownTime = 0L; for (UsageEvents.Event event : events) { - if (Objects.equals(packageName, event.getPackageName())) { - int eventType = event.getEventType(); + int eventType = event.getEventType(); + if (eventType == UsageEvents.Event.DEVICE_SHUTDOWN) { + lastShutdownTime = event.getTimeStamp(); + } else if (Objects.equals(packageName, event.getPackageName())) { // Queries are sorted in descending order, so a not-running activity should be paused // or stopped first and then resumed (i.e., reversed logic) if (isActivityClosed(eventType)) { usage.setLastEndTime(event.getTimeStamp()); } else if (isActivityOpened(eventType)) { + if (lastShutdownTime != 0L) { + // The device was shutdown. Adding the shutdown time here as no impact if + // the event already has an end time. + usage.setLastEndTime(lastShutdownTime); + } usage.setLastStartTime(event.getTimeStamp()); } } @@ -307,12 +315,15 @@ private List getUsageStatsInternal(@UsageUtils.IntervalType in // Get events UsageUtils.TimeInterval interval = UsageUtils.getTimeInterval(usageInterval); List events = UsageStatsManagerCompat.queryEventsSorted(interval.getStartTime(), interval.getEndTime(), userId, USUAL_ACTIVITY_EVENTS); + long lastShutdownTime = 0L; for (UsageEvents.Event event : events) { int eventType = event.getEventType(); String packageName = event.getPackageName(); // Queries are sorted in descending order, so a not-running activity should be paused or // stopped first and then resumed (i.e., reversed logic). - if (isActivityClosed(eventType)) { + if (eventType == UsageEvents.Event.DEVICE_SHUTDOWN) { + lastShutdownTime = event.getTimeStamp(); + } else if (isActivityClosed(eventType)) { PerPackageUsageInternal usage = perPackageUsageMap.get(packageName); if (usage == null) { usage = new PerPackageUsageInternal(packageName); @@ -325,6 +336,11 @@ private List getUsageStatsInternal(@UsageUtils.IntervalType in usage = new PerPackageUsageInternal(packageName); perPackageUsageMap.put(packageName, usage); } + if (lastShutdownTime != 0L) { + // The device was shutdown. Adding the shutdown time here as no impact if the + // event already has an end time. + usage.setLastEndTime(lastShutdownTime); + } usage.setLastStartTime(event.getTimeStamp()); } } @@ -354,8 +370,7 @@ private List getUsageStatsInternal(@UsageUtils.IntervalType in @SuppressLint("InlinedApi") // These are constant values, API compatibility does not apply private static boolean isActivityClosed(int eventType) { return eventType == UsageEvents.Event.ACTIVITY_STOPPED - || eventType == UsageEvents.Event.ACTIVITY_PAUSED - || eventType == UsageEvents.Event.DEVICE_SHUTDOWN; + || eventType == UsageEvents.Event.ACTIVITY_PAUSED; } @SuppressLint("InlinedApi") // These are constant values, API compatibility does not apply