Loading services/core/java/com/android/server/notification/NotificationManagerService.java +46 −29 Original line number Diff line number Diff line Loading @@ -1475,34 +1475,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 @@ -7398,11 +7403,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 @@ -7410,14 +7418,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 @@ -7590,12 +7607,15 @@ public class NotificationManagerService extends SystemService { * notifications visible to the given listener. */ @GuardedBy("mNotificationLock") private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { final int N = mNotificationList.size(); final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>(); for (int i = 0; i < N; i++) { NotificationRecord record = mNotificationList.get(i); if (isInLockDownMode(record.getUser().getIdentifier())) { continue; } if (!isVisibleToListener(record.sbn, info)) { continue; } Loading Loading @@ -7630,8 +7650,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 @@ -7666,7 +7686,8 @@ public class NotificationManagerService extends SystemService { ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE)); } private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { @VisibleForTesting boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { if (!listener.enabledAndUserMatches(sbn.getUserId())) { return false; } Loading Loading @@ -8254,7 +8275,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 @@ -8320,7 +8341,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 @@ -8375,10 +8396,6 @@ public class NotificationManagerService extends SystemService { */ @GuardedBy("mNotificationLock") public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { if (isInLockDownMode()) { return; } boolean isHiddenRankingUpdate = changedHiddenNotifications != null && changedHiddenNotifications.size() > 0; Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +109 −49 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static org.mockito.Mockito.when; import android.app.INotificationManager; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.os.UserHandle; import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; import android.testing.TestableContext; Loading @@ -40,8 +41,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.internal.util.reflection.FieldSetter; import java.util.List; public class NotificationListenersTest extends UiServiceTestCase { @Mock Loading Loading @@ -70,66 +69,127 @@ public class NotificationListenersTest extends UiServiceTestCase { @Test public void testNotifyPostedLockedInLockdownMode() { NotificationRecord r = mock(NotificationRecord.class); NotificationRecord old = mock(NotificationRecord.class); NotificationRecord r0 = mock(NotificationRecord.class); NotificationRecord old0 = mock(NotificationRecord.class); UserHandle uh0 = mock(UserHandle.class); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); mListeners.notifyPostedLocked(r, old, true); mListeners.notifyPostedLocked(r, old, false); verify(mListeners, times(2)).getServices(); 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); // in the lockdown mode reset(r); reset(old); mListeners.notifyPostedLocked(r0, old0, true); mListeners.notifyPostedLocked(r0, old0, false); mListeners.notifyPostedLocked(r1, old1, true); mListeners.notifyPostedLocked(r1, old1, false); verify(mListeners, times(4)).getServices(); // Reset reset(r0); reset(old0); reset(r1); reset(old1); reset(mListeners); when(mNm.isInLockDownMode()).thenReturn(true); mListeners.notifyPostedLocked(r, old, true); mListeners.notifyPostedLocked(r, old, false); // 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(mListeners, never()).getServices(); } @Test public void testnotifyRankingUpdateLockedInLockdownMode() { List chn = mock(List.class); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); mListeners.notifyRankingUpdateLocked(chn); verify(chn, times(1)).size(); // in the lockdown mode reset(chn); when(mNm.isInLockDownMode()).thenReturn(true); mListeners.notifyRankingUpdateLocked(chn); verify(chn, never()).size(); mListeners.notifyPostedLocked(r1, old1, true); mListeners.notifyPostedLocked(r1, old1, false); verify(mListeners, times(2)).getServices(); } @Test public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException { StatusBarNotification sbn = mock(StatusBarNotification.class); NotificationRecord r = mock(NotificationRecord.class); NotificationStats rs = mock(NotificationStats.class); FieldSetter.setField(r, StatusBarNotification sbn0 = mock(StatusBarNotification.class); NotificationRecord r0 = mock(NotificationRecord.class); NotificationStats rs0 = mock(NotificationStats.class); UserHandle uh0 = mock(UserHandle.class); FieldSetter.setField(r0, NotificationRecord.class.getDeclaredField("sbn"), sbn); sbn0); StatusBarNotification sbn1 = mock(StatusBarNotification.class); NotificationRecord r1 = mock(NotificationRecord.class); NotificationStats rs1 = mock(NotificationStats.class); UserHandle uh1 = mock(UserHandle.class); FieldSetter.setField(r1, NotificationRecord.class.getDeclaredField("sbn"), sbn1); FieldSetter.setField(mNm, NotificationManagerService.class.getDeclaredField("mHandler"), mock(NotificationManagerService.WorkerHandler.class)); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); mListeners.notifyRemovedLocked(r, 0, rs); mListeners.notifyRemovedLocked(r, 0, rs); verify(sbn, times(2)).cloneLight(); // in the lockdown mode reset(sbn); reset(r); reset(rs); when(mNm.isInLockDownMode()).thenReturn(true); mListeners.notifyRemovedLocked(r, 0, rs); mListeners.notifyRemovedLocked(r, 0, rs); verify(sbn, never()).cloneLight(); // 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.notifyRemovedLocked(r0, 0, rs0); mListeners.notifyRemovedLocked(r0, 0, rs0); verify(sbn0, times(2)).cloneLight(); mListeners.notifyRemovedLocked(r1, 0, rs1); mListeners.notifyRemovedLocked(r1, 0, rs1); verify(sbn1, times(2)).cloneLight(); // Reset reset(sbn0); reset(r0); reset(rs0); reset(sbn1); reset(r1); reset(rs1); FieldSetter.setField(r0, NotificationRecord.class.getDeclaredField("sbn"), sbn0); FieldSetter.setField(r1, NotificationRecord.class.getDeclaredField("sbn"), sbn1); // 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.notifyRemovedLocked(r0, 0, rs0); mListeners.notifyRemovedLocked(r0, 0, rs0); verify(sbn0, never()).cloneLight(); mListeners.notifyRemovedLocked(r1, 0, rs1); mListeners.notifyRemovedLocked(r1, 0, rs1); verify(sbn1, times(2)).cloneLight(); } } services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +64 −8 Original line number Diff line number Diff line Loading @@ -123,6 +123,7 @@ import android.provider.MediaStore; import android.provider.Settings; import android.service.notification.Adjustment; 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 @@ -148,6 +149,7 @@ import com.android.server.SystemService; import com.android.server.UiServiceTestCase; import com.android.server.lights.Light; import com.android.server.lights.LightsManager; import com.android.server.notification.ManagedServices.ManagedServiceInfo; import com.android.server.notification.NotificationManagerService.NotificationAssistants; import com.android.server.notification.NotificationManagerService.NotificationListeners; import com.android.server.pm.PackageManagerService; Loading Loading @@ -267,6 +269,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Nullable NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback; @Nullable Boolean mIsVisibleToListenerReturnValue = null; TestableNotificationManagerService(Context context, InjectableSystemClock systemClock) { super(context, systemClock); } Loading Loading @@ -347,6 +352,18 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { return true; } protected void setIsVisibleToListenerReturnValue(boolean value) { mIsVisibleToListenerReturnValue = value; } @Override boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { if (mIsVisibleToListenerReturnValue != null) { return mIsVisibleToListenerReturnValue; } return super.isVisibleToListener(sbn, listener); } class StrongAuthTrackerFake extends NotificationManagerService.StrongAuthTracker { private int mGetStrongAuthForUserReturnValue = 0; StrongAuthTrackerFake(Context context) { Loading Loading @@ -442,7 +459,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true); mService.init(mTestableLooper.getLooper(), mPackageManager, mPackageManagerClient, mockLightsManager, mListeners, mAssistants, mConditionProviders, Loading Loading @@ -5519,14 +5535,18 @@ 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 public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() { NotificationManagerService.WorkerHandler mWorkerHandler = spy( mService.new WorkerHandler(mTestableLooper.getLooper())); mService.setHandler(mWorkerHandler); // post 2 notifications from 2 packages NotificationRecord pkgA = new NotificationRecord(mContext, generateSbn("a", 1000, 9, 0), mTestNotificationChannel); Loading @@ -5538,8 +5558,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_LOCKDOWN. ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class); Loading @@ -5548,9 +5568,45 @@ 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); } } Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +46 −29 Original line number Diff line number Diff line Loading @@ -1475,34 +1475,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 @@ -7398,11 +7403,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 @@ -7410,14 +7418,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 @@ -7590,12 +7607,15 @@ public class NotificationManagerService extends SystemService { * notifications visible to the given listener. */ @GuardedBy("mNotificationLock") private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { final int N = mNotificationList.size(); final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>(); for (int i = 0; i < N; i++) { NotificationRecord record = mNotificationList.get(i); if (isInLockDownMode(record.getUser().getIdentifier())) { continue; } if (!isVisibleToListener(record.sbn, info)) { continue; } Loading Loading @@ -7630,8 +7650,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 @@ -7666,7 +7686,8 @@ public class NotificationManagerService extends SystemService { ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE)); } private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { @VisibleForTesting boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { if (!listener.enabledAndUserMatches(sbn.getUserId())) { return false; } Loading Loading @@ -8254,7 +8275,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 @@ -8320,7 +8341,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 @@ -8375,10 +8396,6 @@ public class NotificationManagerService extends SystemService { */ @GuardedBy("mNotificationLock") public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { if (isInLockDownMode()) { return; } boolean isHiddenRankingUpdate = changedHiddenNotifications != null && changedHiddenNotifications.size() > 0; Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +109 −49 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static org.mockito.Mockito.when; import android.app.INotificationManager; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.os.UserHandle; import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; import android.testing.TestableContext; Loading @@ -40,8 +41,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.internal.util.reflection.FieldSetter; import java.util.List; public class NotificationListenersTest extends UiServiceTestCase { @Mock Loading Loading @@ -70,66 +69,127 @@ public class NotificationListenersTest extends UiServiceTestCase { @Test public void testNotifyPostedLockedInLockdownMode() { NotificationRecord r = mock(NotificationRecord.class); NotificationRecord old = mock(NotificationRecord.class); NotificationRecord r0 = mock(NotificationRecord.class); NotificationRecord old0 = mock(NotificationRecord.class); UserHandle uh0 = mock(UserHandle.class); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); mListeners.notifyPostedLocked(r, old, true); mListeners.notifyPostedLocked(r, old, false); verify(mListeners, times(2)).getServices(); 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); // in the lockdown mode reset(r); reset(old); mListeners.notifyPostedLocked(r0, old0, true); mListeners.notifyPostedLocked(r0, old0, false); mListeners.notifyPostedLocked(r1, old1, true); mListeners.notifyPostedLocked(r1, old1, false); verify(mListeners, times(4)).getServices(); // Reset reset(r0); reset(old0); reset(r1); reset(old1); reset(mListeners); when(mNm.isInLockDownMode()).thenReturn(true); mListeners.notifyPostedLocked(r, old, true); mListeners.notifyPostedLocked(r, old, false); // 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(mListeners, never()).getServices(); } @Test public void testnotifyRankingUpdateLockedInLockdownMode() { List chn = mock(List.class); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); mListeners.notifyRankingUpdateLocked(chn); verify(chn, times(1)).size(); // in the lockdown mode reset(chn); when(mNm.isInLockDownMode()).thenReturn(true); mListeners.notifyRankingUpdateLocked(chn); verify(chn, never()).size(); mListeners.notifyPostedLocked(r1, old1, true); mListeners.notifyPostedLocked(r1, old1, false); verify(mListeners, times(2)).getServices(); } @Test public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException { StatusBarNotification sbn = mock(StatusBarNotification.class); NotificationRecord r = mock(NotificationRecord.class); NotificationStats rs = mock(NotificationStats.class); FieldSetter.setField(r, StatusBarNotification sbn0 = mock(StatusBarNotification.class); NotificationRecord r0 = mock(NotificationRecord.class); NotificationStats rs0 = mock(NotificationStats.class); UserHandle uh0 = mock(UserHandle.class); FieldSetter.setField(r0, NotificationRecord.class.getDeclaredField("sbn"), sbn); sbn0); StatusBarNotification sbn1 = mock(StatusBarNotification.class); NotificationRecord r1 = mock(NotificationRecord.class); NotificationStats rs1 = mock(NotificationStats.class); UserHandle uh1 = mock(UserHandle.class); FieldSetter.setField(r1, NotificationRecord.class.getDeclaredField("sbn"), sbn1); FieldSetter.setField(mNm, NotificationManagerService.class.getDeclaredField("mHandler"), mock(NotificationManagerService.WorkerHandler.class)); // before the lockdown mode when(mNm.isInLockDownMode()).thenReturn(false); mListeners.notifyRemovedLocked(r, 0, rs); mListeners.notifyRemovedLocked(r, 0, rs); verify(sbn, times(2)).cloneLight(); // in the lockdown mode reset(sbn); reset(r); reset(rs); when(mNm.isInLockDownMode()).thenReturn(true); mListeners.notifyRemovedLocked(r, 0, rs); mListeners.notifyRemovedLocked(r, 0, rs); verify(sbn, never()).cloneLight(); // 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.notifyRemovedLocked(r0, 0, rs0); mListeners.notifyRemovedLocked(r0, 0, rs0); verify(sbn0, times(2)).cloneLight(); mListeners.notifyRemovedLocked(r1, 0, rs1); mListeners.notifyRemovedLocked(r1, 0, rs1); verify(sbn1, times(2)).cloneLight(); // Reset reset(sbn0); reset(r0); reset(rs0); reset(sbn1); reset(r1); reset(rs1); FieldSetter.setField(r0, NotificationRecord.class.getDeclaredField("sbn"), sbn0); FieldSetter.setField(r1, NotificationRecord.class.getDeclaredField("sbn"), sbn1); // 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.notifyRemovedLocked(r0, 0, rs0); mListeners.notifyRemovedLocked(r0, 0, rs0); verify(sbn0, never()).cloneLight(); mListeners.notifyRemovedLocked(r1, 0, rs1); mListeners.notifyRemovedLocked(r1, 0, rs1); verify(sbn1, times(2)).cloneLight(); } }
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +64 −8 Original line number Diff line number Diff line Loading @@ -123,6 +123,7 @@ import android.provider.MediaStore; import android.provider.Settings; import android.service.notification.Adjustment; 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 @@ -148,6 +149,7 @@ import com.android.server.SystemService; import com.android.server.UiServiceTestCase; import com.android.server.lights.Light; import com.android.server.lights.LightsManager; import com.android.server.notification.ManagedServices.ManagedServiceInfo; import com.android.server.notification.NotificationManagerService.NotificationAssistants; import com.android.server.notification.NotificationManagerService.NotificationListeners; import com.android.server.pm.PackageManagerService; Loading Loading @@ -267,6 +269,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Nullable NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback; @Nullable Boolean mIsVisibleToListenerReturnValue = null; TestableNotificationManagerService(Context context, InjectableSystemClock systemClock) { super(context, systemClock); } Loading Loading @@ -347,6 +352,18 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { return true; } protected void setIsVisibleToListenerReturnValue(boolean value) { mIsVisibleToListenerReturnValue = value; } @Override boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { if (mIsVisibleToListenerReturnValue != null) { return mIsVisibleToListenerReturnValue; } return super.isVisibleToListener(sbn, listener); } class StrongAuthTrackerFake extends NotificationManagerService.StrongAuthTracker { private int mGetStrongAuthForUserReturnValue = 0; StrongAuthTrackerFake(Context context) { Loading Loading @@ -442,7 +459,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true); mService.init(mTestableLooper.getLooper(), mPackageManager, mPackageManagerClient, mockLightsManager, mListeners, mAssistants, mConditionProviders, Loading Loading @@ -5519,14 +5535,18 @@ 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 public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() { NotificationManagerService.WorkerHandler mWorkerHandler = spy( mService.new WorkerHandler(mTestableLooper.getLooper())); mService.setHandler(mWorkerHandler); // post 2 notifications from 2 packages NotificationRecord pkgA = new NotificationRecord(mContext, generateSbn("a", 1000, 9, 0), mTestNotificationChannel); Loading @@ -5538,8 +5558,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_LOCKDOWN. ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class); Loading @@ -5548,9 +5568,45 @@ 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); } }