Loading services/core/java/com/android/server/notification/NotificationManagerService.java +13 −0 Original line number Diff line number Diff line Loading @@ -1929,6 +1929,12 @@ public class NotificationManagerService extends SystemService { hasSensitiveContent, lifespanMs); } protected void logClassificationChannelAdjustmentReceived(boolean hasPosted, boolean isAlerting, int classification, int lifespanMs) { FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_CHANNEL_CLASSIFICATION, hasPosted, isAlerting, classification, lifespanMs); } protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading Loading @@ -6988,8 +6994,15 @@ public class NotificationManagerService extends SystemService { if (newChannel == null || newChannel.getId().equals(r.getChannel().getId())) { adjustments.remove(KEY_TYPE); } else { // Save the app-provided type for logging. int classification = adjustments.getInt(KEY_TYPE); // swap app provided type with the real thing adjustments.putParcelable(KEY_TYPE, newChannel); // Note that this value of isAlerting does not fully indicate whether a notif // would make a sound or HUN on device; it is an approximation for metrics. boolean isAlerting = r.getChannel().getImportance() >= IMPORTANCE_DEFAULT; logClassificationChannelAdjustmentReceived(isPosted, isAlerting, classification, r.getLifespanMs(System.currentTimeMillis())); } } r.addAdjustment(adjustment); Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +57 −0 Original line number Diff line number Diff line Loading @@ -7477,6 +7477,63 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertTrue(mService.checkLastSensitiveLog(true, false, 2)); } @Test @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION) public void testClassificationChannelAdjustmentsLogged() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); // Set up notifications that will be adjusted final NotificationRecord r1 = spy(generateNotificationRecord( mTestNotificationChannel, 1, null, true)); when(r1.getLifespanMs(anyLong())).thenReturn(234); r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); // Enqueues the notification to be posted, so hasPosted will be false. mService.addEnqueuedNotification(r1); // Test an adjustment for an enqueued notification Bundle signals = new Bundle(); signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); Adjustment adjustment1 = new Adjustment( r1.getSbn().getPackageName(), r1.getKey(), signals, "", r1.getUser().getIdentifier()); mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1); assertTrue(mService.checkLastClassificationChannelLog(false /*hasPosted*/, true /*isAlerting*/, 3 /*TYPE_NEWS*/, 234)); // Set up notifications that will be adjusted // This notification starts on a low importance channel, so isAlerting is false. NotificationChannel mLowImportanceNotificationChannel = new NotificationChannel( TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_LOW); final NotificationRecord r2 = spy(generateNotificationRecord( mLowImportanceNotificationChannel, 1, null, true)); when(r2.getLifespanMs(anyLong())).thenReturn(345); r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); // Adds the notification as already posted, so hasPosted will be true. mService.addNotification(r2); // The signal is removed when used so it has to be readded. signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); Adjustment adjustment2 = new Adjustment( r2.getSbn().getPackageName(), r2.getKey(), signals, "", r2.getUser().getIdentifier()); mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2); assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/, false /*isAlerting*/, 3 /*TYPE_NEWS*/, 345)); // currently failing signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_PROMOTION); Adjustment adjustment3 = new Adjustment( r2.getSbn().getPackageName(), r2.getKey(), signals, "", r2.getUser().getIdentifier()); mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3); assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/, false /*isAlerting*/, 1 /*TYPE_PROMOTION*/, 345)); } @Test public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception { NotificationManagerService.WorkerHandler handler = mock( Loading services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java +33 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,14 @@ public class TestableNotificationManagerService extends NotificationManagerServi } public SensitiveLog lastSensitiveLog = null; private static class ClassificationChannelLog { public boolean hasPosted; public boolean isAlerting; public long classification; public long lifetime; } public ClassificationChannelLog lastClassificationChannelLog = null; TestableNotificationManagerService(Context context, NotificationRecordLogger logger, InstanceIdSequence notificationInstanceIdSequence) { super(context, logger, notificationInstanceIdSequence); Loading Loading @@ -211,4 +219,29 @@ public class TestableNotificationManagerService extends NotificationManagerServi public interface ComponentPermissionChecker { int check(String permission, int uid, int owningUid, boolean exported); } @Override protected void logClassificationChannelAdjustmentReceived(boolean hasPosted, boolean isAlerting, int classification, int lifetimeMs) { lastClassificationChannelLog = new ClassificationChannelLog(); lastClassificationChannelLog.hasPosted = hasPosted; lastClassificationChannelLog.isAlerting = isAlerting; lastClassificationChannelLog.classification = classification; lastClassificationChannelLog.lifetime = lifetimeMs; } /** * Returns true if the last recorded classification channel log has all the values specified. */ public boolean checkLastClassificationChannelLog(boolean hasPosted, boolean isAlerting, int classification, int lifetime) { if (lastClassificationChannelLog == null) { return false; } return hasPosted == lastClassificationChannelLog.hasPosted && isAlerting == lastClassificationChannelLog.isAlerting && classification == lastClassificationChannelLog.classification && lifetime == lastClassificationChannelLog.lifetime; } } Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +13 −0 Original line number Diff line number Diff line Loading @@ -1929,6 +1929,12 @@ public class NotificationManagerService extends SystemService { hasSensitiveContent, lifespanMs); } protected void logClassificationChannelAdjustmentReceived(boolean hasPosted, boolean isAlerting, int classification, int lifespanMs) { FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_CHANNEL_CLASSIFICATION, hasPosted, isAlerting, classification, lifespanMs); } protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading Loading @@ -6988,8 +6994,15 @@ public class NotificationManagerService extends SystemService { if (newChannel == null || newChannel.getId().equals(r.getChannel().getId())) { adjustments.remove(KEY_TYPE); } else { // Save the app-provided type for logging. int classification = adjustments.getInt(KEY_TYPE); // swap app provided type with the real thing adjustments.putParcelable(KEY_TYPE, newChannel); // Note that this value of isAlerting does not fully indicate whether a notif // would make a sound or HUN on device; it is an approximation for metrics. boolean isAlerting = r.getChannel().getImportance() >= IMPORTANCE_DEFAULT; logClassificationChannelAdjustmentReceived(isPosted, isAlerting, classification, r.getLifespanMs(System.currentTimeMillis())); } } r.addAdjustment(adjustment); Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +57 −0 Original line number Diff line number Diff line Loading @@ -7477,6 +7477,63 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertTrue(mService.checkLastSensitiveLog(true, false, 2)); } @Test @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION) public void testClassificationChannelAdjustmentsLogged() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); // Set up notifications that will be adjusted final NotificationRecord r1 = spy(generateNotificationRecord( mTestNotificationChannel, 1, null, true)); when(r1.getLifespanMs(anyLong())).thenReturn(234); r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); // Enqueues the notification to be posted, so hasPosted will be false. mService.addEnqueuedNotification(r1); // Test an adjustment for an enqueued notification Bundle signals = new Bundle(); signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); Adjustment adjustment1 = new Adjustment( r1.getSbn().getPackageName(), r1.getKey(), signals, "", r1.getUser().getIdentifier()); mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1); assertTrue(mService.checkLastClassificationChannelLog(false /*hasPosted*/, true /*isAlerting*/, 3 /*TYPE_NEWS*/, 234)); // Set up notifications that will be adjusted // This notification starts on a low importance channel, so isAlerting is false. NotificationChannel mLowImportanceNotificationChannel = new NotificationChannel( TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_LOW); final NotificationRecord r2 = spy(generateNotificationRecord( mLowImportanceNotificationChannel, 1, null, true)); when(r2.getLifespanMs(anyLong())).thenReturn(345); r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); // Adds the notification as already posted, so hasPosted will be true. mService.addNotification(r2); // The signal is removed when used so it has to be readded. signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); Adjustment adjustment2 = new Adjustment( r2.getSbn().getPackageName(), r2.getKey(), signals, "", r2.getUser().getIdentifier()); mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2); assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/, false /*isAlerting*/, 3 /*TYPE_NEWS*/, 345)); // currently failing signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_PROMOTION); Adjustment adjustment3 = new Adjustment( r2.getSbn().getPackageName(), r2.getKey(), signals, "", r2.getUser().getIdentifier()); mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3); assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/, false /*isAlerting*/, 1 /*TYPE_PROMOTION*/, 345)); } @Test public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception { NotificationManagerService.WorkerHandler handler = mock( Loading
services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java +33 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,14 @@ public class TestableNotificationManagerService extends NotificationManagerServi } public SensitiveLog lastSensitiveLog = null; private static class ClassificationChannelLog { public boolean hasPosted; public boolean isAlerting; public long classification; public long lifetime; } public ClassificationChannelLog lastClassificationChannelLog = null; TestableNotificationManagerService(Context context, NotificationRecordLogger logger, InstanceIdSequence notificationInstanceIdSequence) { super(context, logger, notificationInstanceIdSequence); Loading Loading @@ -211,4 +219,29 @@ public class TestableNotificationManagerService extends NotificationManagerServi public interface ComponentPermissionChecker { int check(String permission, int uid, int owningUid, boolean exported); } @Override protected void logClassificationChannelAdjustmentReceived(boolean hasPosted, boolean isAlerting, int classification, int lifetimeMs) { lastClassificationChannelLog = new ClassificationChannelLog(); lastClassificationChannelLog.hasPosted = hasPosted; lastClassificationChannelLog.isAlerting = isAlerting; lastClassificationChannelLog.classification = classification; lastClassificationChannelLog.lifetime = lifetimeMs; } /** * Returns true if the last recorded classification channel log has all the values specified. */ public boolean checkLastClassificationChannelLog(boolean hasPosted, boolean isAlerting, int classification, int lifetime) { if (lastClassificationChannelLog == null) { return false; } return hasPosted == lastClassificationChannelLog.hasPosted && isAlerting == lastClassificationChannelLog.isAlerting && classification == lastClassificationChannelLog.classification && lifetime == lastClassificationChannelLog.lifetime; } }