Loading services/core/java/com/android/server/notification/NotificationManagerService.java +23 −10 Original line number Diff line number Diff line Loading @@ -12577,18 +12577,31 @@ public class NotificationManagerService extends SystemService { // Checks if this is a request to notify system UI about a notification that // has been lifetime extended. // (We only need to check old for the flag, because in both cancellation and // update cases, old should have the flag, whereas in update cases the // new will NOT have the flag.) // If it is such a request, and this is system UI, we send the post request // only to System UI, and break as we don't need to continue checking other // Managed Services. if (info.isSystemUi() && old != null && old.getNotification() != null // We check both old and new for the flag, to avoid catching updates // (where new will not have the flag). // If it is such a request, and this is the system UI listener, we send // the post request. If it's any other listener, we skip it. if (old != null && old.getNotification() != null && (old.getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0 && sbn != null && sbn.getNotification() != null && (sbn.getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) { final NotificationRankingUpdate update = makeRankingUpdateLocked(info); if (info.isSystemUi()) { final NotificationRankingUpdate update = makeRankingUpdateLocked(info); listenerCalls.add(() -> notifyPosted(info, sbnToPost, update)); break; } else { // Skipping because this is the direct-reply "update" and we only // need to send it to sysui, so we immediately continue, before it // can get sent to other listeners below. if (DBG) { Slog.d(TAG, "prepareNotifyPostedLocked: direct reply update, " + "skipping post to " + info.toString()); } continue; } } } services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +209 −10 Original line number Diff line number Diff line Loading @@ -835,7 +835,7 @@ public class NotificationListenersTest extends UiServiceTestCase { } @Test public void testListenerPost_UpdateLifetimeExtended() throws Exception { public void testListenerPostLifetimeExtended_UpdatesOnlySysui() throws Exception { mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR); // Create original notification, with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY. Loading @@ -856,31 +856,51 @@ public class NotificationListenersTest extends UiServiceTestCase { Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId()) .setContentTitle("new title") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, false); .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true); StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0, nb2.build(), userHandle, null, 0); NotificationRecord toPost = new NotificationRecord(mContext, sbn2, channel); // Create system ui-like service. ManagedServices.ManagedServiceInfo info = mListeners.new ManagedServiceInfo( ManagedServices.ManagedServiceInfo sysuiInfo = mListeners.new ManagedServiceInfo( null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33); info.isSystemUi = true; INotificationListener l1 = mock(INotificationListener.class); info.service = l1; List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(info); sysuiInfo.isSystemUi = true; INotificationListener sysuiListener = mock(INotificationListener.class); sysuiInfo.service = sysuiListener; // Create two non-system ui-like services. ManagedServices.ManagedServiceInfo otherInfo1 = mListeners.new ManagedServiceInfo( null, new ComponentName("b", "b"), sbn2.getUserId(), false, null, 33, 33); otherInfo1.isSystemUi = false; INotificationListener otherListener1 = mock(INotificationListener.class); otherInfo1.service = otherListener1; ManagedServices.ManagedServiceInfo otherInfo2 = mListeners.new ManagedServiceInfo( null, new ComponentName("c", "c"), sbn2.getUserId(), false, null, 33, 33); otherInfo2.isSystemUi = false; INotificationListener otherListener2 = mock(INotificationListener.class); otherInfo2.service = otherListener2; List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(otherInfo1, sysuiInfo, otherInfo2); when(mListeners.getServices()).thenReturn(services); FieldSetter.setField(mNm, NotificationManagerService.class.getDeclaredField("mHandler"), mock(NotificationManagerService.WorkerHandler.class)); doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any()); doReturn(mock(NotificationRankingUpdate.class)).when(mNm).makeRankingUpdateLocked(info); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(sysuiInfo); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo1); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo2); doReturn(false).when(mNm).isInLockDownMode(anyInt()); doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt()); doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2); doReturn(sbn2).when(mListeners).redactStatusBarNotification(any()); // The notification change is posted to the service listener. // Post notification change to the service listeners. mListeners.notifyPostedLocked(toPost, old); // Verify that the post occcurs with the updated notification value. Loading @@ -889,11 +909,190 @@ public class NotificationListenersTest extends UiServiceTestCase { runnableCaptor.getValue().run(); ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor = ArgumentCaptor.forClass(IStatusBarNotificationHolder.class); verify(l1, times(1)).onNotificationPosted(sbnCaptor.capture(), any()); verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any()); StatusBarNotification sbnResult = sbnCaptor.getValue().get(); assertThat(sbnResult.getNotification() .extras.getCharSequence(Notification.EXTRA_TITLE).toString()) .isEqualTo("new title"); verify(otherListener1, never()).onNotificationPosted(any(), any()); verify(otherListener2, never()).onNotificationPosted(any(), any()); } @Test public void testListenerPostLifeimteExtension_postsToAppropriateListeners() throws Exception { mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR); // Create original notification, with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY. String pkg = "pkg"; int uid = 9; UserHandle userHandle = UserHandle.getUserHandleForUid(uid); NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH); Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true); StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0, nb.build(), userHandle, null, 0); NotificationRecord leRecord = new NotificationRecord(mContext, sbn, channel); // Creates updated notification (without FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId()) .setContentTitle("new title") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, false); StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0, nb2.build(), userHandle, null, 0); NotificationRecord nonLeRecord = new NotificationRecord(mContext, sbn2, channel); // Create system ui-like service. ManagedServices.ManagedServiceInfo sysuiInfo = mListeners.new ManagedServiceInfo( null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33); sysuiInfo.isSystemUi = true; INotificationListener sysuiListener = mock(INotificationListener.class); sysuiInfo.service = sysuiListener; // Create two non-system ui-like services. ManagedServices.ManagedServiceInfo otherInfo1 = mListeners.new ManagedServiceInfo( null, new ComponentName("b", "b"), sbn2.getUserId(), false, null, 33, 33); otherInfo1.isSystemUi = false; INotificationListener otherListener1 = mock(INotificationListener.class); otherInfo1.service = otherListener1; ManagedServices.ManagedServiceInfo otherInfo2 = mListeners.new ManagedServiceInfo( null, new ComponentName("c", "c"), sbn2.getUserId(), false, null, 33, 33); otherInfo2.isSystemUi = false; INotificationListener otherListener2 = mock(INotificationListener.class); otherInfo2.service = otherListener2; List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(otherInfo1, sysuiInfo, otherInfo2); when(mListeners.getServices()).thenReturn(services); FieldSetter.setField(mNm, NotificationManagerService.class.getDeclaredField("mHandler"), mock(NotificationManagerService.WorkerHandler.class)); doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any()); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(sysuiInfo); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo1); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo2); doReturn(false).when(mNm).isInLockDownMode(anyInt()); doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt()); doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2); doReturn(sbn2).when(mListeners).redactStatusBarNotification(any()); // The notification change is posted to the service listener. // NonLE to LE should never happen, as LE can't be set in an update by the app. // So we just want to test LE to NonLE. mListeners.notifyPostedLocked(nonLeRecord /*=toPost*/, leRecord /*=old*/); // Verify that the post occcurs with the updated notification value. ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); verify(mNm.mHandler, times(3)).post(runnableCaptor.capture()); List<Runnable> capturedRunnable = runnableCaptor.getAllValues(); for (Runnable r : capturedRunnable) { r.run(); } ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor = ArgumentCaptor.forClass(IStatusBarNotificationHolder.class); verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any()); StatusBarNotification sbnResult = sbnCaptor.getValue().get(); assertThat(sbnResult.getNotification() .extras.getCharSequence(Notification.EXTRA_TITLE).toString()) .isEqualTo("new title"); verify(otherListener1, times(1)).onNotificationPosted(any(), any()); verify(otherListener2, times(1)).onNotificationPosted(any(), any()); } @Test public void testNotifyPostedLocked_postsToAppropriateListeners() throws Exception { // Create original notification String pkg = "pkg"; int uid = 9; UserHandle userHandle = UserHandle.getUserHandleForUid(uid); NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH); Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon); StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0, nb.build(), userHandle, null, 0); NotificationRecord oldRecord = new NotificationRecord(mContext, sbn, channel); // Creates updated notification Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId()) .setContentTitle("new title") .setSmallIcon(android.R.drawable.sym_def_app_icon); StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0, nb2.build(), userHandle, null, 0); NotificationRecord newRecord = new NotificationRecord(mContext, sbn2, channel); // Create system ui-like service. ManagedServices.ManagedServiceInfo sysuiInfo = mListeners.new ManagedServiceInfo( null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33); sysuiInfo.isSystemUi = true; INotificationListener sysuiListener = mock(INotificationListener.class); sysuiInfo.service = sysuiListener; // Create two non-system ui-like services. ManagedServices.ManagedServiceInfo otherInfo1 = mListeners.new ManagedServiceInfo( null, new ComponentName("b", "b"), sbn2.getUserId(), false, null, 33, 33); otherInfo1.isSystemUi = false; INotificationListener otherListener1 = mock(INotificationListener.class); otherInfo1.service = otherListener1; ManagedServices.ManagedServiceInfo otherInfo2 = mListeners.new ManagedServiceInfo( null, new ComponentName("c", "c"), sbn2.getUserId(), false, null, 33, 33); otherInfo2.isSystemUi = false; INotificationListener otherListener2 = mock(INotificationListener.class); otherInfo2.service = otherListener2; List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(otherInfo1, sysuiInfo, otherInfo2); when(mListeners.getServices()).thenReturn(services); FieldSetter.setField(mNm, NotificationManagerService.class.getDeclaredField("mHandler"), mock(NotificationManagerService.WorkerHandler.class)); doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any()); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(sysuiInfo); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo1); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo2); doReturn(false).when(mNm).isInLockDownMode(anyInt()); doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt()); doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2); doReturn(sbn2).when(mListeners).redactStatusBarNotification(any()); // The notification change is posted to the service listeners. mListeners.notifyPostedLocked(newRecord, oldRecord); // Verify that the post occcurs with the updated notification value. ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); verify(mNm.mHandler, times(3)).post(runnableCaptor.capture()); List<Runnable> capturedRunnable = runnableCaptor.getAllValues(); for (Runnable r : capturedRunnable) { r.run(); } ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor = ArgumentCaptor.forClass(IStatusBarNotificationHolder.class); verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any()); StatusBarNotification sbnResult = sbnCaptor.getValue().get(); assertThat(sbnResult.getNotification() .extras.getCharSequence(Notification.EXTRA_TITLE).toString()) .isEqualTo("new title"); verify(otherListener1, times(1)).onNotificationPosted(any(), any()); verify(otherListener2, times(1)).onNotificationPosted(any(), any()); } /** Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +23 −10 Original line number Diff line number Diff line Loading @@ -12577,18 +12577,31 @@ public class NotificationManagerService extends SystemService { // Checks if this is a request to notify system UI about a notification that // has been lifetime extended. // (We only need to check old for the flag, because in both cancellation and // update cases, old should have the flag, whereas in update cases the // new will NOT have the flag.) // If it is such a request, and this is system UI, we send the post request // only to System UI, and break as we don't need to continue checking other // Managed Services. if (info.isSystemUi() && old != null && old.getNotification() != null // We check both old and new for the flag, to avoid catching updates // (where new will not have the flag). // If it is such a request, and this is the system UI listener, we send // the post request. If it's any other listener, we skip it. if (old != null && old.getNotification() != null && (old.getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0 && sbn != null && sbn.getNotification() != null && (sbn.getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) { final NotificationRankingUpdate update = makeRankingUpdateLocked(info); if (info.isSystemUi()) { final NotificationRankingUpdate update = makeRankingUpdateLocked(info); listenerCalls.add(() -> notifyPosted(info, sbnToPost, update)); break; } else { // Skipping because this is the direct-reply "update" and we only // need to send it to sysui, so we immediately continue, before it // can get sent to other listeners below. if (DBG) { Slog.d(TAG, "prepareNotifyPostedLocked: direct reply update, " + "skipping post to " + info.toString()); } continue; } } }
services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +209 −10 Original line number Diff line number Diff line Loading @@ -835,7 +835,7 @@ public class NotificationListenersTest extends UiServiceTestCase { } @Test public void testListenerPost_UpdateLifetimeExtended() throws Exception { public void testListenerPostLifetimeExtended_UpdatesOnlySysui() throws Exception { mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR); // Create original notification, with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY. Loading @@ -856,31 +856,51 @@ public class NotificationListenersTest extends UiServiceTestCase { Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId()) .setContentTitle("new title") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, false); .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true); StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0, nb2.build(), userHandle, null, 0); NotificationRecord toPost = new NotificationRecord(mContext, sbn2, channel); // Create system ui-like service. ManagedServices.ManagedServiceInfo info = mListeners.new ManagedServiceInfo( ManagedServices.ManagedServiceInfo sysuiInfo = mListeners.new ManagedServiceInfo( null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33); info.isSystemUi = true; INotificationListener l1 = mock(INotificationListener.class); info.service = l1; List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(info); sysuiInfo.isSystemUi = true; INotificationListener sysuiListener = mock(INotificationListener.class); sysuiInfo.service = sysuiListener; // Create two non-system ui-like services. ManagedServices.ManagedServiceInfo otherInfo1 = mListeners.new ManagedServiceInfo( null, new ComponentName("b", "b"), sbn2.getUserId(), false, null, 33, 33); otherInfo1.isSystemUi = false; INotificationListener otherListener1 = mock(INotificationListener.class); otherInfo1.service = otherListener1; ManagedServices.ManagedServiceInfo otherInfo2 = mListeners.new ManagedServiceInfo( null, new ComponentName("c", "c"), sbn2.getUserId(), false, null, 33, 33); otherInfo2.isSystemUi = false; INotificationListener otherListener2 = mock(INotificationListener.class); otherInfo2.service = otherListener2; List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(otherInfo1, sysuiInfo, otherInfo2); when(mListeners.getServices()).thenReturn(services); FieldSetter.setField(mNm, NotificationManagerService.class.getDeclaredField("mHandler"), mock(NotificationManagerService.WorkerHandler.class)); doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any()); doReturn(mock(NotificationRankingUpdate.class)).when(mNm).makeRankingUpdateLocked(info); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(sysuiInfo); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo1); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo2); doReturn(false).when(mNm).isInLockDownMode(anyInt()); doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt()); doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2); doReturn(sbn2).when(mListeners).redactStatusBarNotification(any()); // The notification change is posted to the service listener. // Post notification change to the service listeners. mListeners.notifyPostedLocked(toPost, old); // Verify that the post occcurs with the updated notification value. Loading @@ -889,11 +909,190 @@ public class NotificationListenersTest extends UiServiceTestCase { runnableCaptor.getValue().run(); ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor = ArgumentCaptor.forClass(IStatusBarNotificationHolder.class); verify(l1, times(1)).onNotificationPosted(sbnCaptor.capture(), any()); verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any()); StatusBarNotification sbnResult = sbnCaptor.getValue().get(); assertThat(sbnResult.getNotification() .extras.getCharSequence(Notification.EXTRA_TITLE).toString()) .isEqualTo("new title"); verify(otherListener1, never()).onNotificationPosted(any(), any()); verify(otherListener2, never()).onNotificationPosted(any(), any()); } @Test public void testListenerPostLifeimteExtension_postsToAppropriateListeners() throws Exception { mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR); // Create original notification, with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY. String pkg = "pkg"; int uid = 9; UserHandle userHandle = UserHandle.getUserHandleForUid(uid); NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH); Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true); StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0, nb.build(), userHandle, null, 0); NotificationRecord leRecord = new NotificationRecord(mContext, sbn, channel); // Creates updated notification (without FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId()) .setContentTitle("new title") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, false); StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0, nb2.build(), userHandle, null, 0); NotificationRecord nonLeRecord = new NotificationRecord(mContext, sbn2, channel); // Create system ui-like service. ManagedServices.ManagedServiceInfo sysuiInfo = mListeners.new ManagedServiceInfo( null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33); sysuiInfo.isSystemUi = true; INotificationListener sysuiListener = mock(INotificationListener.class); sysuiInfo.service = sysuiListener; // Create two non-system ui-like services. ManagedServices.ManagedServiceInfo otherInfo1 = mListeners.new ManagedServiceInfo( null, new ComponentName("b", "b"), sbn2.getUserId(), false, null, 33, 33); otherInfo1.isSystemUi = false; INotificationListener otherListener1 = mock(INotificationListener.class); otherInfo1.service = otherListener1; ManagedServices.ManagedServiceInfo otherInfo2 = mListeners.new ManagedServiceInfo( null, new ComponentName("c", "c"), sbn2.getUserId(), false, null, 33, 33); otherInfo2.isSystemUi = false; INotificationListener otherListener2 = mock(INotificationListener.class); otherInfo2.service = otherListener2; List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(otherInfo1, sysuiInfo, otherInfo2); when(mListeners.getServices()).thenReturn(services); FieldSetter.setField(mNm, NotificationManagerService.class.getDeclaredField("mHandler"), mock(NotificationManagerService.WorkerHandler.class)); doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any()); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(sysuiInfo); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo1); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo2); doReturn(false).when(mNm).isInLockDownMode(anyInt()); doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt()); doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2); doReturn(sbn2).when(mListeners).redactStatusBarNotification(any()); // The notification change is posted to the service listener. // NonLE to LE should never happen, as LE can't be set in an update by the app. // So we just want to test LE to NonLE. mListeners.notifyPostedLocked(nonLeRecord /*=toPost*/, leRecord /*=old*/); // Verify that the post occcurs with the updated notification value. ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); verify(mNm.mHandler, times(3)).post(runnableCaptor.capture()); List<Runnable> capturedRunnable = runnableCaptor.getAllValues(); for (Runnable r : capturedRunnable) { r.run(); } ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor = ArgumentCaptor.forClass(IStatusBarNotificationHolder.class); verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any()); StatusBarNotification sbnResult = sbnCaptor.getValue().get(); assertThat(sbnResult.getNotification() .extras.getCharSequence(Notification.EXTRA_TITLE).toString()) .isEqualTo("new title"); verify(otherListener1, times(1)).onNotificationPosted(any(), any()); verify(otherListener2, times(1)).onNotificationPosted(any(), any()); } @Test public void testNotifyPostedLocked_postsToAppropriateListeners() throws Exception { // Create original notification String pkg = "pkg"; int uid = 9; UserHandle userHandle = UserHandle.getUserHandleForUid(uid); NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH); Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon); StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0, nb.build(), userHandle, null, 0); NotificationRecord oldRecord = new NotificationRecord(mContext, sbn, channel); // Creates updated notification Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId()) .setContentTitle("new title") .setSmallIcon(android.R.drawable.sym_def_app_icon); StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0, nb2.build(), userHandle, null, 0); NotificationRecord newRecord = new NotificationRecord(mContext, sbn2, channel); // Create system ui-like service. ManagedServices.ManagedServiceInfo sysuiInfo = mListeners.new ManagedServiceInfo( null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33); sysuiInfo.isSystemUi = true; INotificationListener sysuiListener = mock(INotificationListener.class); sysuiInfo.service = sysuiListener; // Create two non-system ui-like services. ManagedServices.ManagedServiceInfo otherInfo1 = mListeners.new ManagedServiceInfo( null, new ComponentName("b", "b"), sbn2.getUserId(), false, null, 33, 33); otherInfo1.isSystemUi = false; INotificationListener otherListener1 = mock(INotificationListener.class); otherInfo1.service = otherListener1; ManagedServices.ManagedServiceInfo otherInfo2 = mListeners.new ManagedServiceInfo( null, new ComponentName("c", "c"), sbn2.getUserId(), false, null, 33, 33); otherInfo2.isSystemUi = false; INotificationListener otherListener2 = mock(INotificationListener.class); otherInfo2.service = otherListener2; List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(otherInfo1, sysuiInfo, otherInfo2); when(mListeners.getServices()).thenReturn(services); FieldSetter.setField(mNm, NotificationManagerService.class.getDeclaredField("mHandler"), mock(NotificationManagerService.WorkerHandler.class)); doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any()); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(sysuiInfo); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo1); doReturn(mock(NotificationRankingUpdate.class)).when(mNm) .makeRankingUpdateLocked(otherInfo2); doReturn(false).when(mNm).isInLockDownMode(anyInt()); doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt()); doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2); doReturn(sbn2).when(mListeners).redactStatusBarNotification(any()); // The notification change is posted to the service listeners. mListeners.notifyPostedLocked(newRecord, oldRecord); // Verify that the post occcurs with the updated notification value. ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); verify(mNm.mHandler, times(3)).post(runnableCaptor.capture()); List<Runnable> capturedRunnable = runnableCaptor.getAllValues(); for (Runnable r : capturedRunnable) { r.run(); } ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor = ArgumentCaptor.forClass(IStatusBarNotificationHolder.class); verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any()); StatusBarNotification sbnResult = sbnCaptor.getValue().get(); assertThat(sbnResult.getNotification() .extras.getCharSequence(Notification.EXTRA_TITLE).toString()) .isEqualTo("new title"); verify(otherListener1, times(1)).onNotificationPosted(any(), any()); verify(otherListener2, times(1)).onNotificationPosted(any(), any()); } /** Loading