Loading services/core/java/com/android/server/notification/NotificationManagerService.java +43 −27 Original line number Diff line number Diff line Loading @@ -1978,34 +1978,39 @@ public class NotificationManagerService extends SystemService { return (haystack & needle) != 0; } public boolean isInLockDownMode() { return mIsInLockDownMode; // Return whether the user is in lockdown mode. // If the flag is not set, we assume the user is not in lockdown. public boolean isInLockDownMode(int userId) { return mUserInLockDownMode.get(userId, false); } @Override public synchronized void onStrongAuthRequiredChanged(int userId) { boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId), STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); mUserInLockDownMode.put(userId, userInLockDownModeNext); boolean isInLockDownModeNext = mUserInLockDownMode.indexOfValue(true) != -1; if (mIsInLockDownMode == isInLockDownModeNext) { // Nothing happens if the lockdown mode of userId keeps the same. if (userInLockDownModeNext == isInLockDownMode(userId)) { return; } if (isInLockDownModeNext) { cancelNotificationsWhenEnterLockDownMode(); // When the lockdown mode is changed, we perform the following steps. // If the userInLockDownModeNext is true, all the function calls to // notifyPostedLocked and notifyRemovedLocked will not be executed. // The cancelNotificationsWhenEnterLockDownMode calls notifyRemovedLocked // and postNotificationsWhenExitLockDownMode calls notifyPostedLocked. // So we shall call cancelNotificationsWhenEnterLockDownMode before // we set mUserInLockDownMode as true. // On the other hand, if the userInLockDownModeNext is false, we shall call // postNotificationsWhenExitLockDownMode after we put false into mUserInLockDownMode if (userInLockDownModeNext) { cancelNotificationsWhenEnterLockDownMode(userId); } // When the mIsInLockDownMode is true, both notifyPostedLocked and // notifyRemovedLocked will be dismissed. So we shall call // cancelNotificationsWhenEnterLockDownMode before we set mIsInLockDownMode // as true and call postNotificationsWhenExitLockDownMode after we set // mIsInLockDownMode as false. mIsInLockDownMode = isInLockDownModeNext; mUserInLockDownMode.put(userId, userInLockDownModeNext); if (!isInLockDownModeNext) { postNotificationsWhenExitLockDownMode(); if (!userInLockDownModeNext) { postNotificationsWhenExitLockDownMode(userId); } } } Loading Loading @@ -9679,11 +9684,14 @@ public class NotificationManagerService extends SystemService { } } private void cancelNotificationsWhenEnterLockDownMode() { private void cancelNotificationsWhenEnterLockDownMode(int userId) { synchronized (mNotificationLock) { int numNotifications = mNotificationList.size(); for (int i = 0; i < numNotifications; i++) { NotificationRecord rec = mNotificationList.get(i); if (rec.getUser().getIdentifier() != userId) { continue; } mListeners.notifyRemovedLocked(rec, REASON_CANCEL_ALL, rec.getStats()); } Loading @@ -9691,14 +9699,23 @@ public class NotificationManagerService extends SystemService { } } private void postNotificationsWhenExitLockDownMode() { private void postNotificationsWhenExitLockDownMode(int userId) { synchronized (mNotificationLock) { int numNotifications = mNotificationList.size(); // Set the delay to spread out the burst of notifications. long delay = 0; for (int i = 0; i < numNotifications; i++) { NotificationRecord rec = mNotificationList.get(i); if (rec.getUser().getIdentifier() != userId) { continue; } mHandler.postDelayed(() -> { synchronized (mNotificationLock) { mListeners.notifyPostedLocked(rec, rec); } }, delay); delay += 20; } } } Loading Loading @@ -9877,6 +9894,9 @@ public class NotificationManagerService extends SystemService { for (int i = 0; i < N; i++) { NotificationRecord record = mNotificationList.get(i); if (isInLockDownMode(record.getUser().getIdentifier())) { continue; } if (!isVisibleToListener(record.getSbn(), record.getNotificationType(), info)) { continue; } Loading Loading @@ -9918,8 +9938,8 @@ public class NotificationManagerService extends SystemService { rankings.toArray(new NotificationListenerService.Ranking[0])); } boolean isInLockDownMode() { return mStrongAuthTracker.isInLockDownMode(); boolean isInLockDownMode(int userId) { return mStrongAuthTracker.isInLockDownMode(userId); } boolean hasCompanionDevice(ManagedServiceInfo info) { Loading Loading @@ -10989,7 +11009,7 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") void notifyPostedLocked(NotificationRecord r, NotificationRecord old, boolean notifyAllListeners) { if (isInLockDownMode()) { if (isInLockDownMode(r.getUser().getIdentifier())) { return; } Loading Loading @@ -11095,7 +11115,7 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") public void notifyRemovedLocked(NotificationRecord r, int reason, NotificationStats notificationStats) { if (isInLockDownMode()) { if (isInLockDownMode(r.getUser().getIdentifier())) { return; } Loading Loading @@ -11144,10 +11164,6 @@ public class NotificationManagerService extends SystemService { */ @GuardedBy("mNotificationLock") public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { if (isInLockDownMode()) { return; } boolean isHiddenRankingUpdate = changedHiddenNotifications != null && changedHiddenNotifications.size() > 0; // TODO (b/73052211): if the ranking update changed the notification type, Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +98 −49 Original line number Diff line number Diff line Loading @@ -488,63 +488,112 @@ public class NotificationListenersTest extends UiServiceTestCase { @Test public void testNotifyPostedLockedInLockdownMode() { NotificationRecord r = mock(NotificationRecord.class); NotificationRecord old = mock(NotificationRecord.class); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); mListeners.notifyPostedLocked(r, old, true); mListeners.notifyPostedLocked(r, old, false); verify(r, atLeast(2)).getSbn(); // in the lockdown mode reset(r); reset(old); when(mNm.isInLockDownMode()).thenReturn(true); mListeners.notifyPostedLocked(r, old, true); mListeners.notifyPostedLocked(r, old, false); verify(r, never()).getSbn(); } @Test public void testnotifyRankingUpdateLockedInLockdownMode() { List chn = mock(List.class); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); mListeners.notifyRankingUpdateLocked(chn); verify(chn, atLeast(1)).size(); // in the lockdown mode reset(chn); when(mNm.isInLockDownMode()).thenReturn(true); mListeners.notifyRankingUpdateLocked(chn); verify(chn, never()).size(); NotificationRecord r0 = mock(NotificationRecord.class); NotificationRecord old0 = mock(NotificationRecord.class); UserHandle uh0 = mock(UserHandle.class); NotificationRecord r1 = mock(NotificationRecord.class); NotificationRecord old1 = mock(NotificationRecord.class); UserHandle uh1 = mock(UserHandle.class); // Neither user0 and user1 is in the lockdown mode when(r0.getUser()).thenReturn(uh0); when(uh0.getIdentifier()).thenReturn(0); when(mNm.isInLockDownMode(0)).thenReturn(false); when(r1.getUser()).thenReturn(uh1); when(uh1.getIdentifier()).thenReturn(1); when(mNm.isInLockDownMode(1)).thenReturn(false); mListeners.notifyPostedLocked(r0, old0, true); mListeners.notifyPostedLocked(r0, old0, false); verify(r0, atLeast(2)).getSbn(); mListeners.notifyPostedLocked(r1, old1, true); mListeners.notifyPostedLocked(r1, old1, false); verify(r1, atLeast(2)).getSbn(); // Reset reset(r0); reset(old0); reset(r1); reset(old1); // Only user 0 is in the lockdown mode when(r0.getUser()).thenReturn(uh0); when(uh0.getIdentifier()).thenReturn(0); when(mNm.isInLockDownMode(0)).thenReturn(true); when(r1.getUser()).thenReturn(uh1); when(uh1.getIdentifier()).thenReturn(1); when(mNm.isInLockDownMode(1)).thenReturn(false); mListeners.notifyPostedLocked(r0, old0, true); mListeners.notifyPostedLocked(r0, old0, false); verify(r0, never()).getSbn(); mListeners.notifyPostedLocked(r1, old1, true); mListeners.notifyPostedLocked(r1, old1, false); verify(r1, atLeast(2)).getSbn(); } @Test public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException { NotificationRecord r = mock(NotificationRecord.class); NotificationStats rs = mock(NotificationStats.class); NotificationRecord r0 = mock(NotificationRecord.class); NotificationStats rs0 = mock(NotificationStats.class); UserHandle uh0 = mock(UserHandle.class); NotificationRecord r1 = mock(NotificationRecord.class); NotificationStats rs1 = mock(NotificationStats.class); UserHandle uh1 = mock(UserHandle.class); StatusBarNotification sbn = mock(StatusBarNotification.class); FieldSetter.setField(mNm, NotificationManagerService.class.getDeclaredField("mHandler"), mock(NotificationManagerService.WorkerHandler.class)); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); when(r.getSbn()).thenReturn(sbn); mListeners.notifyRemovedLocked(r, 0, rs); mListeners.notifyRemovedLocked(r, 0, rs); verify(r, atLeast(2)).getSbn(); // in the lockdown mode reset(r); reset(rs); when(mNm.isInLockDownMode()).thenReturn(true); when(r.getSbn()).thenReturn(sbn); mListeners.notifyRemovedLocked(r, 0, rs); mListeners.notifyRemovedLocked(r, 0, rs); verify(r, never()).getSbn(); // Neither user0 and user1 is in the lockdown mode when(r0.getUser()).thenReturn(uh0); when(uh0.getIdentifier()).thenReturn(0); when(mNm.isInLockDownMode(0)).thenReturn(false); when(r0.getSbn()).thenReturn(sbn); when(r1.getUser()).thenReturn(uh1); when(uh1.getIdentifier()).thenReturn(1); when(mNm.isInLockDownMode(1)).thenReturn(false); when(r1.getSbn()).thenReturn(sbn); mListeners.notifyRemovedLocked(r0, 0, rs0); mListeners.notifyRemovedLocked(r0, 0, rs0); verify(r0, atLeast(2)).getSbn(); mListeners.notifyRemovedLocked(r1, 0, rs1); mListeners.notifyRemovedLocked(r1, 0, rs1); verify(r1, atLeast(2)).getSbn(); // Reset reset(r0); reset(rs0); reset(r1); reset(rs1); // Only user 0 is in the lockdown mode when(r0.getUser()).thenReturn(uh0); when(uh0.getIdentifier()).thenReturn(0); when(mNm.isInLockDownMode(0)).thenReturn(true); when(r0.getSbn()).thenReturn(sbn); when(r1.getUser()).thenReturn(uh1); when(uh1.getIdentifier()).thenReturn(1); when(mNm.isInLockDownMode(1)).thenReturn(false); when(r1.getSbn()).thenReturn(sbn); mListeners.notifyRemovedLocked(r0, 0, rs0); mListeners.notifyRemovedLocked(r0, 0, rs0); verify(r0, never()).getSbn(); mListeners.notifyRemovedLocked(r1, 0, rs1); mListeners.notifyRemovedLocked(r1, 0, rs1); verify(r1, atLeast(2)).getSbn(); } } services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +44 −7 Original line number Diff line number Diff line Loading @@ -174,6 +174,7 @@ import android.service.notification.Adjustment; import android.service.notification.ConversationChannelWrapper; import android.service.notification.NotificationListenerFilter; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationRankingUpdate; import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; import android.service.notification.ZenPolicy; Loading Loading @@ -9781,10 +9782,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mStrongAuthTracker.setGetStrongAuthForUserReturnValue( STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); assertTrue(mStrongAuthTracker.isInLockDownMode()); mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); assertTrue(mStrongAuthTracker.isInLockDownMode(mContext.getUserId())); mStrongAuthTracker.setGetStrongAuthForUserReturnValue(mContext.getUserId()); mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); assertFalse(mStrongAuthTracker.isInLockDownMode()); assertFalse(mStrongAuthTracker.isInLockDownMode(mContext.getUserId())); } @Test Loading @@ -9800,8 +9801,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // when entering the lockdown mode, cancel the 2 notifications. mStrongAuthTracker.setGetStrongAuthForUserReturnValue( STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); assertTrue(mStrongAuthTracker.isInLockDownMode()); mStrongAuthTracker.onStrongAuthRequiredChanged(0); assertTrue(mStrongAuthTracker.isInLockDownMode(0)); // the notifyRemovedLocked function is called twice due to REASON_CANCEL_ALL. ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class); Loading @@ -9810,10 +9811,46 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // exit lockdown mode. mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); mStrongAuthTracker.onStrongAuthRequiredChanged(0); assertFalse(mStrongAuthTracker.isInLockDownMode(0)); // the notifyPostedLocked function is called twice. verify(mListeners, times(2)).notifyPostedLocked(any(), any()); verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong()); //verify(mListeners, times(2)).notifyPostedLocked(any(), any()); } @Test public void testMakeRankingUpdateLockedInLockDownMode() { // post 2 notifications from a same package NotificationRecord pkgA = new NotificationRecord(mContext, generateSbn("a", 1000, 9, 0), mTestNotificationChannel); mService.addNotification(pkgA); NotificationRecord pkgB = new NotificationRecord(mContext, generateSbn("a", 1000, 9, 1), mTestNotificationChannel); mService.addNotification(pkgB); mService.setIsVisibleToListenerReturnValue(true); NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(null); assertEquals(2, nru.getRankingMap().getOrderedKeys().length); // when only user 0 entering the lockdown mode, its notification will be suppressed. mStrongAuthTracker.setGetStrongAuthForUserReturnValue( STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); mStrongAuthTracker.onStrongAuthRequiredChanged(0); assertTrue(mStrongAuthTracker.isInLockDownMode(0)); assertFalse(mStrongAuthTracker.isInLockDownMode(1)); nru = mService.makeRankingUpdateLocked(null); assertEquals(1, nru.getRankingMap().getOrderedKeys().length); // User 0 exits lockdown mode. Its notification will be resumed. mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); mStrongAuthTracker.onStrongAuthRequiredChanged(0); assertFalse(mStrongAuthTracker.isInLockDownMode(0)); assertFalse(mStrongAuthTracker.isInLockDownMode(1)); nru = mService.makeRankingUpdateLocked(null); assertEquals(2, nru.getRankingMap().getOrderedKeys().length); } @Test Loading services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java +18 −0 Original line number Diff line number Diff line Loading @@ -19,10 +19,12 @@ package com.android.server.notification; import android.companion.ICompanionDeviceManager; import android.content.ComponentName; import android.content.Context; import android.service.notification.StatusBarNotification; import androidx.annotation.Nullable; import com.android.internal.logging.InstanceIdSequence; import com.android.server.notification.ManagedServices.ManagedServiceInfo; import java.util.HashSet; import java.util.Set; Loading @@ -37,6 +39,9 @@ public class TestableNotificationManagerService extends NotificationManagerServi @Nullable NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback; @Nullable Boolean mIsVisibleToListenerReturnValue = null; TestableNotificationManagerService(Context context, NotificationRecordLogger logger, InstanceIdSequence notificationInstanceIdSequence) { super(context, logger, notificationInstanceIdSequence); Loading Loading @@ -119,6 +124,19 @@ public class TestableNotificationManagerService extends NotificationManagerServi mShowReviewPermissionsNotification = setting; } protected void setIsVisibleToListenerReturnValue(boolean value) { mIsVisibleToListenerReturnValue = value; } @Override boolean isVisibleToListener(StatusBarNotification sbn, int notificationType, ManagedServiceInfo listener) { if (mIsVisibleToListenerReturnValue != null) { return mIsVisibleToListenerReturnValue; } return super.isVisibleToListener(sbn, notificationType, listener); } public class StrongAuthTrackerFake extends NotificationManagerService.StrongAuthTracker { private int mGetStrongAuthForUserReturnValue = 0; StrongAuthTrackerFake(Context context) { Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +43 −27 Original line number Diff line number Diff line Loading @@ -1978,34 +1978,39 @@ public class NotificationManagerService extends SystemService { return (haystack & needle) != 0; } public boolean isInLockDownMode() { return mIsInLockDownMode; // Return whether the user is in lockdown mode. // If the flag is not set, we assume the user is not in lockdown. public boolean isInLockDownMode(int userId) { return mUserInLockDownMode.get(userId, false); } @Override public synchronized void onStrongAuthRequiredChanged(int userId) { boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId), STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); mUserInLockDownMode.put(userId, userInLockDownModeNext); boolean isInLockDownModeNext = mUserInLockDownMode.indexOfValue(true) != -1; if (mIsInLockDownMode == isInLockDownModeNext) { // Nothing happens if the lockdown mode of userId keeps the same. if (userInLockDownModeNext == isInLockDownMode(userId)) { return; } if (isInLockDownModeNext) { cancelNotificationsWhenEnterLockDownMode(); // When the lockdown mode is changed, we perform the following steps. // If the userInLockDownModeNext is true, all the function calls to // notifyPostedLocked and notifyRemovedLocked will not be executed. // The cancelNotificationsWhenEnterLockDownMode calls notifyRemovedLocked // and postNotificationsWhenExitLockDownMode calls notifyPostedLocked. // So we shall call cancelNotificationsWhenEnterLockDownMode before // we set mUserInLockDownMode as true. // On the other hand, if the userInLockDownModeNext is false, we shall call // postNotificationsWhenExitLockDownMode after we put false into mUserInLockDownMode if (userInLockDownModeNext) { cancelNotificationsWhenEnterLockDownMode(userId); } // When the mIsInLockDownMode is true, both notifyPostedLocked and // notifyRemovedLocked will be dismissed. So we shall call // cancelNotificationsWhenEnterLockDownMode before we set mIsInLockDownMode // as true and call postNotificationsWhenExitLockDownMode after we set // mIsInLockDownMode as false. mIsInLockDownMode = isInLockDownModeNext; mUserInLockDownMode.put(userId, userInLockDownModeNext); if (!isInLockDownModeNext) { postNotificationsWhenExitLockDownMode(); if (!userInLockDownModeNext) { postNotificationsWhenExitLockDownMode(userId); } } } Loading Loading @@ -9679,11 +9684,14 @@ public class NotificationManagerService extends SystemService { } } private void cancelNotificationsWhenEnterLockDownMode() { private void cancelNotificationsWhenEnterLockDownMode(int userId) { synchronized (mNotificationLock) { int numNotifications = mNotificationList.size(); for (int i = 0; i < numNotifications; i++) { NotificationRecord rec = mNotificationList.get(i); if (rec.getUser().getIdentifier() != userId) { continue; } mListeners.notifyRemovedLocked(rec, REASON_CANCEL_ALL, rec.getStats()); } Loading @@ -9691,14 +9699,23 @@ public class NotificationManagerService extends SystemService { } } private void postNotificationsWhenExitLockDownMode() { private void postNotificationsWhenExitLockDownMode(int userId) { synchronized (mNotificationLock) { int numNotifications = mNotificationList.size(); // Set the delay to spread out the burst of notifications. long delay = 0; for (int i = 0; i < numNotifications; i++) { NotificationRecord rec = mNotificationList.get(i); if (rec.getUser().getIdentifier() != userId) { continue; } mHandler.postDelayed(() -> { synchronized (mNotificationLock) { mListeners.notifyPostedLocked(rec, rec); } }, delay); delay += 20; } } } Loading Loading @@ -9877,6 +9894,9 @@ public class NotificationManagerService extends SystemService { for (int i = 0; i < N; i++) { NotificationRecord record = mNotificationList.get(i); if (isInLockDownMode(record.getUser().getIdentifier())) { continue; } if (!isVisibleToListener(record.getSbn(), record.getNotificationType(), info)) { continue; } Loading Loading @@ -9918,8 +9938,8 @@ public class NotificationManagerService extends SystemService { rankings.toArray(new NotificationListenerService.Ranking[0])); } boolean isInLockDownMode() { return mStrongAuthTracker.isInLockDownMode(); boolean isInLockDownMode(int userId) { return mStrongAuthTracker.isInLockDownMode(userId); } boolean hasCompanionDevice(ManagedServiceInfo info) { Loading Loading @@ -10989,7 +11009,7 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") void notifyPostedLocked(NotificationRecord r, NotificationRecord old, boolean notifyAllListeners) { if (isInLockDownMode()) { if (isInLockDownMode(r.getUser().getIdentifier())) { return; } Loading Loading @@ -11095,7 +11115,7 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") public void notifyRemovedLocked(NotificationRecord r, int reason, NotificationStats notificationStats) { if (isInLockDownMode()) { if (isInLockDownMode(r.getUser().getIdentifier())) { return; } Loading Loading @@ -11144,10 +11164,6 @@ public class NotificationManagerService extends SystemService { */ @GuardedBy("mNotificationLock") public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { if (isInLockDownMode()) { return; } boolean isHiddenRankingUpdate = changedHiddenNotifications != null && changedHiddenNotifications.size() > 0; // TODO (b/73052211): if the ranking update changed the notification type, Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +98 −49 Original line number Diff line number Diff line Loading @@ -488,63 +488,112 @@ public class NotificationListenersTest extends UiServiceTestCase { @Test public void testNotifyPostedLockedInLockdownMode() { NotificationRecord r = mock(NotificationRecord.class); NotificationRecord old = mock(NotificationRecord.class); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); mListeners.notifyPostedLocked(r, old, true); mListeners.notifyPostedLocked(r, old, false); verify(r, atLeast(2)).getSbn(); // in the lockdown mode reset(r); reset(old); when(mNm.isInLockDownMode()).thenReturn(true); mListeners.notifyPostedLocked(r, old, true); mListeners.notifyPostedLocked(r, old, false); verify(r, never()).getSbn(); } @Test public void testnotifyRankingUpdateLockedInLockdownMode() { List chn = mock(List.class); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); mListeners.notifyRankingUpdateLocked(chn); verify(chn, atLeast(1)).size(); // in the lockdown mode reset(chn); when(mNm.isInLockDownMode()).thenReturn(true); mListeners.notifyRankingUpdateLocked(chn); verify(chn, never()).size(); NotificationRecord r0 = mock(NotificationRecord.class); NotificationRecord old0 = mock(NotificationRecord.class); UserHandle uh0 = mock(UserHandle.class); NotificationRecord r1 = mock(NotificationRecord.class); NotificationRecord old1 = mock(NotificationRecord.class); UserHandle uh1 = mock(UserHandle.class); // Neither user0 and user1 is in the lockdown mode when(r0.getUser()).thenReturn(uh0); when(uh0.getIdentifier()).thenReturn(0); when(mNm.isInLockDownMode(0)).thenReturn(false); when(r1.getUser()).thenReturn(uh1); when(uh1.getIdentifier()).thenReturn(1); when(mNm.isInLockDownMode(1)).thenReturn(false); mListeners.notifyPostedLocked(r0, old0, true); mListeners.notifyPostedLocked(r0, old0, false); verify(r0, atLeast(2)).getSbn(); mListeners.notifyPostedLocked(r1, old1, true); mListeners.notifyPostedLocked(r1, old1, false); verify(r1, atLeast(2)).getSbn(); // Reset reset(r0); reset(old0); reset(r1); reset(old1); // Only user 0 is in the lockdown mode when(r0.getUser()).thenReturn(uh0); when(uh0.getIdentifier()).thenReturn(0); when(mNm.isInLockDownMode(0)).thenReturn(true); when(r1.getUser()).thenReturn(uh1); when(uh1.getIdentifier()).thenReturn(1); when(mNm.isInLockDownMode(1)).thenReturn(false); mListeners.notifyPostedLocked(r0, old0, true); mListeners.notifyPostedLocked(r0, old0, false); verify(r0, never()).getSbn(); mListeners.notifyPostedLocked(r1, old1, true); mListeners.notifyPostedLocked(r1, old1, false); verify(r1, atLeast(2)).getSbn(); } @Test public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException { NotificationRecord r = mock(NotificationRecord.class); NotificationStats rs = mock(NotificationStats.class); NotificationRecord r0 = mock(NotificationRecord.class); NotificationStats rs0 = mock(NotificationStats.class); UserHandle uh0 = mock(UserHandle.class); NotificationRecord r1 = mock(NotificationRecord.class); NotificationStats rs1 = mock(NotificationStats.class); UserHandle uh1 = mock(UserHandle.class); StatusBarNotification sbn = mock(StatusBarNotification.class); FieldSetter.setField(mNm, NotificationManagerService.class.getDeclaredField("mHandler"), mock(NotificationManagerService.WorkerHandler.class)); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); when(r.getSbn()).thenReturn(sbn); mListeners.notifyRemovedLocked(r, 0, rs); mListeners.notifyRemovedLocked(r, 0, rs); verify(r, atLeast(2)).getSbn(); // in the lockdown mode reset(r); reset(rs); when(mNm.isInLockDownMode()).thenReturn(true); when(r.getSbn()).thenReturn(sbn); mListeners.notifyRemovedLocked(r, 0, rs); mListeners.notifyRemovedLocked(r, 0, rs); verify(r, never()).getSbn(); // Neither user0 and user1 is in the lockdown mode when(r0.getUser()).thenReturn(uh0); when(uh0.getIdentifier()).thenReturn(0); when(mNm.isInLockDownMode(0)).thenReturn(false); when(r0.getSbn()).thenReturn(sbn); when(r1.getUser()).thenReturn(uh1); when(uh1.getIdentifier()).thenReturn(1); when(mNm.isInLockDownMode(1)).thenReturn(false); when(r1.getSbn()).thenReturn(sbn); mListeners.notifyRemovedLocked(r0, 0, rs0); mListeners.notifyRemovedLocked(r0, 0, rs0); verify(r0, atLeast(2)).getSbn(); mListeners.notifyRemovedLocked(r1, 0, rs1); mListeners.notifyRemovedLocked(r1, 0, rs1); verify(r1, atLeast(2)).getSbn(); // Reset reset(r0); reset(rs0); reset(r1); reset(rs1); // Only user 0 is in the lockdown mode when(r0.getUser()).thenReturn(uh0); when(uh0.getIdentifier()).thenReturn(0); when(mNm.isInLockDownMode(0)).thenReturn(true); when(r0.getSbn()).thenReturn(sbn); when(r1.getUser()).thenReturn(uh1); when(uh1.getIdentifier()).thenReturn(1); when(mNm.isInLockDownMode(1)).thenReturn(false); when(r1.getSbn()).thenReturn(sbn); mListeners.notifyRemovedLocked(r0, 0, rs0); mListeners.notifyRemovedLocked(r0, 0, rs0); verify(r0, never()).getSbn(); mListeners.notifyRemovedLocked(r1, 0, rs1); mListeners.notifyRemovedLocked(r1, 0, rs1); verify(r1, atLeast(2)).getSbn(); } }
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +44 −7 Original line number Diff line number Diff line Loading @@ -174,6 +174,7 @@ import android.service.notification.Adjustment; import android.service.notification.ConversationChannelWrapper; import android.service.notification.NotificationListenerFilter; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationRankingUpdate; import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; import android.service.notification.ZenPolicy; Loading Loading @@ -9781,10 +9782,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mStrongAuthTracker.setGetStrongAuthForUserReturnValue( STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); assertTrue(mStrongAuthTracker.isInLockDownMode()); mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); assertTrue(mStrongAuthTracker.isInLockDownMode(mContext.getUserId())); mStrongAuthTracker.setGetStrongAuthForUserReturnValue(mContext.getUserId()); mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); assertFalse(mStrongAuthTracker.isInLockDownMode()); assertFalse(mStrongAuthTracker.isInLockDownMode(mContext.getUserId())); } @Test Loading @@ -9800,8 +9801,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // when entering the lockdown mode, cancel the 2 notifications. mStrongAuthTracker.setGetStrongAuthForUserReturnValue( STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); assertTrue(mStrongAuthTracker.isInLockDownMode()); mStrongAuthTracker.onStrongAuthRequiredChanged(0); assertTrue(mStrongAuthTracker.isInLockDownMode(0)); // the notifyRemovedLocked function is called twice due to REASON_CANCEL_ALL. ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class); Loading @@ -9810,10 +9811,46 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // exit lockdown mode. mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); mStrongAuthTracker.onStrongAuthRequiredChanged(0); assertFalse(mStrongAuthTracker.isInLockDownMode(0)); // the notifyPostedLocked function is called twice. verify(mListeners, times(2)).notifyPostedLocked(any(), any()); verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong()); //verify(mListeners, times(2)).notifyPostedLocked(any(), any()); } @Test public void testMakeRankingUpdateLockedInLockDownMode() { // post 2 notifications from a same package NotificationRecord pkgA = new NotificationRecord(mContext, generateSbn("a", 1000, 9, 0), mTestNotificationChannel); mService.addNotification(pkgA); NotificationRecord pkgB = new NotificationRecord(mContext, generateSbn("a", 1000, 9, 1), mTestNotificationChannel); mService.addNotification(pkgB); mService.setIsVisibleToListenerReturnValue(true); NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(null); assertEquals(2, nru.getRankingMap().getOrderedKeys().length); // when only user 0 entering the lockdown mode, its notification will be suppressed. mStrongAuthTracker.setGetStrongAuthForUserReturnValue( STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); mStrongAuthTracker.onStrongAuthRequiredChanged(0); assertTrue(mStrongAuthTracker.isInLockDownMode(0)); assertFalse(mStrongAuthTracker.isInLockDownMode(1)); nru = mService.makeRankingUpdateLocked(null); assertEquals(1, nru.getRankingMap().getOrderedKeys().length); // User 0 exits lockdown mode. Its notification will be resumed. mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); mStrongAuthTracker.onStrongAuthRequiredChanged(0); assertFalse(mStrongAuthTracker.isInLockDownMode(0)); assertFalse(mStrongAuthTracker.isInLockDownMode(1)); nru = mService.makeRankingUpdateLocked(null); assertEquals(2, nru.getRankingMap().getOrderedKeys().length); } @Test Loading
services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java +18 −0 Original line number Diff line number Diff line Loading @@ -19,10 +19,12 @@ package com.android.server.notification; import android.companion.ICompanionDeviceManager; import android.content.ComponentName; import android.content.Context; import android.service.notification.StatusBarNotification; import androidx.annotation.Nullable; import com.android.internal.logging.InstanceIdSequence; import com.android.server.notification.ManagedServices.ManagedServiceInfo; import java.util.HashSet; import java.util.Set; Loading @@ -37,6 +39,9 @@ public class TestableNotificationManagerService extends NotificationManagerServi @Nullable NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback; @Nullable Boolean mIsVisibleToListenerReturnValue = null; TestableNotificationManagerService(Context context, NotificationRecordLogger logger, InstanceIdSequence notificationInstanceIdSequence) { super(context, logger, notificationInstanceIdSequence); Loading Loading @@ -119,6 +124,19 @@ public class TestableNotificationManagerService extends NotificationManagerServi mShowReviewPermissionsNotification = setting; } protected void setIsVisibleToListenerReturnValue(boolean value) { mIsVisibleToListenerReturnValue = value; } @Override boolean isVisibleToListener(StatusBarNotification sbn, int notificationType, ManagedServiceInfo listener) { if (mIsVisibleToListenerReturnValue != null) { return mIsVisibleToListenerReturnValue; } return super.isVisibleToListener(sbn, notificationType, listener); } public class StrongAuthTrackerFake extends NotificationManagerService.StrongAuthTracker { private int mGetStrongAuthForUserReturnValue = 0; StrongAuthTrackerFake(Context context) { Loading