Loading core/java/android/app/usage/UsageEvents.java +6 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,12 @@ public final class UsageEvents implements Parcelable { */ public static final int CHOOSER_ACTION = 9; /** * An event type denoting that a notification was viewed by the user. * @hide */ public static final int NOTIFICATION_SEEN = 10; /** @hide */ public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0; Loading services/core/java/com/android/server/notification/NotificationManagerService.java +14 −4 Original line number Diff line number Diff line Loading @@ -736,6 +736,11 @@ public class NotificationManagerService extends SystemService { for (NotificationVisibility nv : newlyVisibleKeys) { NotificationRecord r = mNotificationsByKey.get(nv.key); if (r == null) continue; if (!r.isSeen()) { // Report to usage stats that notification was made visible if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key); reportSeen(r); } r.setVisibility(true, nv.rank); nv.recycle(); } Loading Loading @@ -1643,6 +1648,14 @@ public class NotificationManagerService extends SystemService { return INotificationManager.Stub.asInterface(mService); } protected void reportSeen(NotificationRecord r) { final int userId = r.sbn.getUserId(); mAppUsageStats.reportEvent(r.sbn.getPackageName(), userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId, UsageEvents.Event.NOTIFICATION_SEEN); } @VisibleForTesting NotificationManagerInternal getInternalService() { return mInternalService; Loading Loading @@ -2269,10 +2282,7 @@ public class NotificationManagerService extends SystemService { } if (!r.isSeen()) { if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); mAppUsageStats.reportEvent(r.sbn.getPackageName(), userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId, UsageEvents.Event.USER_INTERACTION); reportSeen(r); r.setSeen(); } } Loading services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +8 −1 Original line number Diff line number Diff line Loading @@ -144,7 +144,9 @@ public class NotificationManagerServiceTest extends NotificationTestCase { // Use a Testable subclass so we can simulate calls from the system without failing. private static class TestableNotificationManagerService extends NotificationManagerService { public TestableNotificationManagerService(Context context) { super(context); } public TestableNotificationManagerService(Context context) { super(context); } @Override protected boolean isCallingUidSystem() { Loading @@ -160,6 +162,11 @@ public class NotificationManagerServiceTest extends NotificationTestCase { protected ICompanionDeviceManager getCompanionManager() { return null; } @Override protected void reportSeen(NotificationRecord r) { return; } } @Before Loading services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +32 −10 Original line number Diff line number Diff line Loading @@ -17,6 +17,9 @@ package com.android.server.usage; import static android.app.usage.AppStandby.*; import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN; import static android.app.usage.UsageEvents.Event.USER_INTERACTION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; Loading Loading @@ -247,21 +250,27 @@ public class AppStandbyControllerTests { false)); } private void reportEvent(AppStandbyController controller, long elapsedTime) { private void reportEvent(AppStandbyController controller, int eventType, long elapsedTime) { // Back to ACTIVE on event UsageEvents.Event ev = new UsageEvents.Event(); ev.mPackage = PACKAGE_1; ev.mEventType = UsageEvents.Event.USER_INTERACTION; ev.mEventType = eventType; controller.reportEvent(ev, elapsedTime, USER_ID); } private int getStandbyBucket(AppStandbyController controller) { return controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, true); } @Test public void testBuckets() throws Exception { AppStandbyController controller = setupController(); assertTimeout(controller, 0, STANDBY_BUCKET_NEVER); reportEvent(controller, 0); reportEvent(controller, USER_INTERACTION, 0); // ACTIVE bucket assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE); Loading @@ -278,7 +287,7 @@ public class AppStandbyControllerTests { // RARE bucket assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_RARE); reportEvent(controller, 9 * DAY_MS); reportEvent(controller, USER_INTERACTION, 9 * DAY_MS); assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_ACTIVE); Loading @@ -293,7 +302,7 @@ public class AppStandbyControllerTests { assertTimeout(controller, 0, STANDBY_BUCKET_NEVER); reportEvent(controller, 0); reportEvent(controller, USER_INTERACTION, 0); // ACTIVE bucket assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE); Loading @@ -304,9 +313,7 @@ public class AppStandbyControllerTests { // RARE bucket, should fail because the screen wasn't ON. mInjector.mElapsedRealtime = 9 * DAY_MS; controller.checkIdleStates(USER_ID); assertNotEquals(STANDBY_BUCKET_RARE, controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, false)); assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller)); mInjector.setDisplayOn(true); assertTimeout(controller, 18 * DAY_MS, STANDBY_BUCKET_RARE); Loading @@ -318,8 +325,7 @@ public class AppStandbyControllerTests { setChargingState(controller, false); controller.forceIdleState(PACKAGE_1, USER_ID, true); assertEquals(STANDBY_BUCKET_RARE, controller.getAppStandbyBucket(PACKAGE_1, USER_ID, 0, true)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller)); assertTrue(controller.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); controller.forceIdleState(PACKAGE_1, USER_ID, false); Loading @@ -327,4 +333,20 @@ public class AppStandbyControllerTests { true)); assertFalse(controller.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); } @Test public void testNotificationEvent() throws Exception { AppStandbyController controller = setupController(); setChargingState(controller, false); reportEvent(controller, USER_INTERACTION, 0); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller)); mInjector.mElapsedRealtime = 1; reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller)); controller.forceIdleState(PACKAGE_1, USER_ID, true); reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller)); } } services/usage/java/com/android/server/usage/AppIdleHistory.java +26 −5 Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ public class AppIdleHistory { writeScreenOnTime(); } public void reportUsage(String packageName, int userId, long elapsedRealtime) { public int reportUsage(String packageName, int userId, long elapsedRealtime) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, elapsedRealtime, true); Loading @@ -197,13 +197,34 @@ public class AppIdleHistory { + (elapsedRealtime - mElapsedSnapshot); appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime); appUsageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE; appUsageHistory.currentBucket = AppStandby.STANDBY_BUCKET_ACTIVE; if (appUsageHistory.currentBucket > STANDBY_BUCKET_ACTIVE) { appUsageHistory.currentBucket = STANDBY_BUCKET_ACTIVE; if (DEBUG) { Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket + ", reason=" + appUsageHistory.bucketingReason); } } appUsageHistory.bucketingReason = AppStandby.REASON_USAGE; return appUsageHistory.currentBucket; } public int reportMildUsage(String packageName, int userId, long elapsedRealtime) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, elapsedRealtime, true); if (appUsageHistory.currentBucket > STANDBY_BUCKET_WORKING_SET) { appUsageHistory.currentBucket = STANDBY_BUCKET_WORKING_SET; if (DEBUG) { Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket + ", reason=" + appUsageHistory.bucketingReason); } } // TODO: Should this be a different reason for partial usage? appUsageHistory.bucketingReason = AppStandby.REASON_USAGE; return appUsageHistory.currentBucket; } public void setIdle(String packageName, int userId, long elapsedRealtime) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); Loading Loading
core/java/android/app/usage/UsageEvents.java +6 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,12 @@ public final class UsageEvents implements Parcelable { */ public static final int CHOOSER_ACTION = 9; /** * An event type denoting that a notification was viewed by the user. * @hide */ public static final int NOTIFICATION_SEEN = 10; /** @hide */ public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0; Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +14 −4 Original line number Diff line number Diff line Loading @@ -736,6 +736,11 @@ public class NotificationManagerService extends SystemService { for (NotificationVisibility nv : newlyVisibleKeys) { NotificationRecord r = mNotificationsByKey.get(nv.key); if (r == null) continue; if (!r.isSeen()) { // Report to usage stats that notification was made visible if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key); reportSeen(r); } r.setVisibility(true, nv.rank); nv.recycle(); } Loading Loading @@ -1643,6 +1648,14 @@ public class NotificationManagerService extends SystemService { return INotificationManager.Stub.asInterface(mService); } protected void reportSeen(NotificationRecord r) { final int userId = r.sbn.getUserId(); mAppUsageStats.reportEvent(r.sbn.getPackageName(), userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId, UsageEvents.Event.NOTIFICATION_SEEN); } @VisibleForTesting NotificationManagerInternal getInternalService() { return mInternalService; Loading Loading @@ -2269,10 +2282,7 @@ public class NotificationManagerService extends SystemService { } if (!r.isSeen()) { if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); mAppUsageStats.reportEvent(r.sbn.getPackageName(), userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId, UsageEvents.Event.USER_INTERACTION); reportSeen(r); r.setSeen(); } } Loading
services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +8 −1 Original line number Diff line number Diff line Loading @@ -144,7 +144,9 @@ public class NotificationManagerServiceTest extends NotificationTestCase { // Use a Testable subclass so we can simulate calls from the system without failing. private static class TestableNotificationManagerService extends NotificationManagerService { public TestableNotificationManagerService(Context context) { super(context); } public TestableNotificationManagerService(Context context) { super(context); } @Override protected boolean isCallingUidSystem() { Loading @@ -160,6 +162,11 @@ public class NotificationManagerServiceTest extends NotificationTestCase { protected ICompanionDeviceManager getCompanionManager() { return null; } @Override protected void reportSeen(NotificationRecord r) { return; } } @Before Loading
services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +32 −10 Original line number Diff line number Diff line Loading @@ -17,6 +17,9 @@ package com.android.server.usage; import static android.app.usage.AppStandby.*; import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN; import static android.app.usage.UsageEvents.Event.USER_INTERACTION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; Loading Loading @@ -247,21 +250,27 @@ public class AppStandbyControllerTests { false)); } private void reportEvent(AppStandbyController controller, long elapsedTime) { private void reportEvent(AppStandbyController controller, int eventType, long elapsedTime) { // Back to ACTIVE on event UsageEvents.Event ev = new UsageEvents.Event(); ev.mPackage = PACKAGE_1; ev.mEventType = UsageEvents.Event.USER_INTERACTION; ev.mEventType = eventType; controller.reportEvent(ev, elapsedTime, USER_ID); } private int getStandbyBucket(AppStandbyController controller) { return controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, true); } @Test public void testBuckets() throws Exception { AppStandbyController controller = setupController(); assertTimeout(controller, 0, STANDBY_BUCKET_NEVER); reportEvent(controller, 0); reportEvent(controller, USER_INTERACTION, 0); // ACTIVE bucket assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE); Loading @@ -278,7 +287,7 @@ public class AppStandbyControllerTests { // RARE bucket assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_RARE); reportEvent(controller, 9 * DAY_MS); reportEvent(controller, USER_INTERACTION, 9 * DAY_MS); assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_ACTIVE); Loading @@ -293,7 +302,7 @@ public class AppStandbyControllerTests { assertTimeout(controller, 0, STANDBY_BUCKET_NEVER); reportEvent(controller, 0); reportEvent(controller, USER_INTERACTION, 0); // ACTIVE bucket assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE); Loading @@ -304,9 +313,7 @@ public class AppStandbyControllerTests { // RARE bucket, should fail because the screen wasn't ON. mInjector.mElapsedRealtime = 9 * DAY_MS; controller.checkIdleStates(USER_ID); assertNotEquals(STANDBY_BUCKET_RARE, controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, false)); assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller)); mInjector.setDisplayOn(true); assertTimeout(controller, 18 * DAY_MS, STANDBY_BUCKET_RARE); Loading @@ -318,8 +325,7 @@ public class AppStandbyControllerTests { setChargingState(controller, false); controller.forceIdleState(PACKAGE_1, USER_ID, true); assertEquals(STANDBY_BUCKET_RARE, controller.getAppStandbyBucket(PACKAGE_1, USER_ID, 0, true)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller)); assertTrue(controller.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); controller.forceIdleState(PACKAGE_1, USER_ID, false); Loading @@ -327,4 +333,20 @@ public class AppStandbyControllerTests { true)); assertFalse(controller.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); } @Test public void testNotificationEvent() throws Exception { AppStandbyController controller = setupController(); setChargingState(controller, false); reportEvent(controller, USER_INTERACTION, 0); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller)); mInjector.mElapsedRealtime = 1; reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller)); controller.forceIdleState(PACKAGE_1, USER_ID, true); reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller)); } }
services/usage/java/com/android/server/usage/AppIdleHistory.java +26 −5 Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ public class AppIdleHistory { writeScreenOnTime(); } public void reportUsage(String packageName, int userId, long elapsedRealtime) { public int reportUsage(String packageName, int userId, long elapsedRealtime) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, elapsedRealtime, true); Loading @@ -197,13 +197,34 @@ public class AppIdleHistory { + (elapsedRealtime - mElapsedSnapshot); appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime); appUsageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE; appUsageHistory.currentBucket = AppStandby.STANDBY_BUCKET_ACTIVE; if (appUsageHistory.currentBucket > STANDBY_BUCKET_ACTIVE) { appUsageHistory.currentBucket = STANDBY_BUCKET_ACTIVE; if (DEBUG) { Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket + ", reason=" + appUsageHistory.bucketingReason); } } appUsageHistory.bucketingReason = AppStandby.REASON_USAGE; return appUsageHistory.currentBucket; } public int reportMildUsage(String packageName, int userId, long elapsedRealtime) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, elapsedRealtime, true); if (appUsageHistory.currentBucket > STANDBY_BUCKET_WORKING_SET) { appUsageHistory.currentBucket = STANDBY_BUCKET_WORKING_SET; if (DEBUG) { Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket + ", reason=" + appUsageHistory.bucketingReason); } } // TODO: Should this be a different reason for partial usage? appUsageHistory.bucketingReason = AppStandby.REASON_USAGE; return appUsageHistory.currentBucket; } public void setIdle(String packageName, int userId, long elapsedRealtime) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); Loading