Loading core/api/current.txt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -39069,6 +39069,7 @@ package android.service.notification { field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc field public static final int REASON_LISTENER_CANCEL = 10; // 0xa field public static final int REASON_LISTENER_CANCEL = 10; // 0xa field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb field public static final int REASON_LOCKDOWN = 22; // 0x16 field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe core/java/android/service/notification/NotificationListenerService.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -258,6 +258,8 @@ public abstract class NotificationListenerService extends Service { public static final int REASON_CLEAR_DATA = 21; public static final int REASON_CLEAR_DATA = 21; /** Notification was canceled due to an assistant adjustment update. */ /** Notification was canceled due to an assistant adjustment update. */ public static final int REASON_ASSISTANT_CANCEL = 22; public static final int REASON_ASSISTANT_CANCEL = 22; /** Notification was canceled when lockdown mode is enabled. */ public static final int REASON_LOCKDOWN = 22; /** /** * @hide * @hide Loading Loading @@ -285,6 +287,7 @@ public abstract class NotificationListenerService extends Service { REASON_CHANNEL_REMOVED, REASON_CHANNEL_REMOVED, REASON_CLEAR_DATA, REASON_CLEAR_DATA, REASON_ASSISTANT_CANCEL, REASON_ASSISTANT_CANCEL, REASON_LOCKDOWN, }) }) public @interface NotificationCancelReason{}; public @interface NotificationCancelReason{}; Loading services/core/java/com/android/server/notification/NotificationManagerService.java +99 −1 Original line number Original line Diff line number Diff line Loading @@ -94,6 +94,7 @@ import static android.service.notification.NotificationListenerService.REASON_ER import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED; Loading Loading @@ -252,6 +253,7 @@ import android.util.Log; import android.util.Pair; import android.util.Pair; import android.util.Slog; import android.util.Slog; import android.util.SparseArray; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.StatsEvent; import android.util.StatsEvent; import android.util.TypedXmlPullParser; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import android.util.TypedXmlSerializer; Loading Loading @@ -284,6 +286,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.TriPredicate; import com.android.internal.util.function.TriPredicate; import com.android.internal.widget.LockPatternUtils; import com.android.server.DeviceIdleInternal; import com.android.server.DeviceIdleInternal; import com.android.server.EventLogTags; import com.android.server.EventLogTags; import com.android.server.IoThread; import com.android.server.IoThread; Loading Loading @@ -1914,6 +1917,54 @@ public class NotificationManagerService extends SystemService { private SettingsObserver mSettingsObserver; private SettingsObserver mSettingsObserver; protected ZenModeHelper mZenModeHelper; protected ZenModeHelper mZenModeHelper; protected class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker { SparseBooleanArray mUserInLockDownMode = new SparseBooleanArray(); boolean mIsInLockDownMode = false; StrongAuthTracker(Context context) { super(context); } private boolean containsFlag(int haystack, int needle) { return (haystack & needle) != 0; } public boolean isInLockDownMode() { return mIsInLockDownMode; } @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) { return; } if (isInLockDownModeNext) { cancelNotificationsWhenEnterLockDownMode(); } // 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; if (!isInLockDownModeNext) { postNotificationsWhenExitLockDownMode(); } } } private LockPatternUtils mLockPatternUtils; private StrongAuthTracker mStrongAuthTracker; public NotificationManagerService(Context context) { public NotificationManagerService(Context context) { this(context, this(context, new NotificationRecordLoggerImpl(), new NotificationRecordLoggerImpl(), Loading Loading @@ -1942,6 +1993,11 @@ public class NotificationManagerService extends SystemService { mAudioManager = audioMananger; mAudioManager = audioMananger; } } @VisibleForTesting void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) { mStrongAuthTracker = strongAuthTracker; } @VisibleForTesting @VisibleForTesting void setKeyguardManager(KeyguardManager keyguardManager) { void setKeyguardManager(KeyguardManager keyguardManager) { mKeyguardManager = keyguardManager; mKeyguardManager = keyguardManager; Loading Loading @@ -2136,6 +2192,8 @@ public class NotificationManagerService extends SystemService { mPlatformCompat = IPlatformCompat.Stub.asInterface( mPlatformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mLockPatternUtils = new LockPatternUtils(getContext()); mStrongAuthTracker = new StrongAuthTracker(getContext()); mUiHandler = new Handler(UiThread.get().getLooper()); mUiHandler = new Handler(UiThread.get().getLooper()); String[] extractorNames; String[] extractorNames; try { try { Loading Loading @@ -2632,6 +2690,7 @@ public class NotificationManagerService extends SystemService { bubbsExtractor.setShortcutHelper(mShortcutHelper); bubbsExtractor.setShortcutHelper(mShortcutHelper); } } registerNotificationPreferencesPullers(); registerNotificationPreferencesPullers(); mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { // This observer will force an update when observe is called, causing us to // This observer will force an update when observe is called, causing us to // bind to listener services. // bind to listener services. Loading Loading @@ -9528,6 +9587,29 @@ public class NotificationManagerService extends SystemService { } } } } private void cancelNotificationsWhenEnterLockDownMode() { synchronized (mNotificationLock) { int numNotifications = mNotificationList.size(); for (int i = 0; i < numNotifications; i++) { NotificationRecord rec = mNotificationList.get(i); mListeners.notifyRemovedLocked(rec, REASON_LOCKDOWN, rec.getStats()); } } } private void postNotificationsWhenExitLockDownMode() { synchronized (mNotificationLock) { int numNotifications = mNotificationList.size(); for (int i = 0; i < numNotifications; i++) { NotificationRecord rec = mNotificationList.get(i); mListeners.notifyPostedLocked(rec, rec); } } } private void updateNotificationPulse() { private void updateNotificationPulse() { synchronized (mNotificationLock) { synchronized (mNotificationLock) { updateLightsLocked(); updateLightsLocked(); Loading Loading @@ -9744,6 +9826,10 @@ public class NotificationManagerService extends SystemService { rankings.toArray(new NotificationListenerService.Ranking[0])); rankings.toArray(new NotificationListenerService.Ranking[0])); } } boolean isInLockDownMode() { return mStrongAuthTracker.isInLockDownMode(); } boolean hasCompanionDevice(ManagedServiceInfo info) { boolean hasCompanionDevice(ManagedServiceInfo info) { if (mCompanionManager == null) { if (mCompanionManager == null) { mCompanionManager = getCompanionManager(); mCompanionManager = getCompanionManager(); Loading Loading @@ -10795,8 +10881,12 @@ public class NotificationManagerService extends SystemService { * targetting <= O_MR1 * targetting <= O_MR1 */ */ @GuardedBy("mNotificationLock") @GuardedBy("mNotificationLock") private void notifyPostedLocked(NotificationRecord r, NotificationRecord old, void notifyPostedLocked(NotificationRecord r, NotificationRecord old, boolean notifyAllListeners) { boolean notifyAllListeners) { if (isInLockDownMode()) { return; } try { try { // Lazily initialized snapshots of the notification. // Lazily initialized snapshots of the notification. StatusBarNotification sbn = r.getSbn(); StatusBarNotification sbn = r.getSbn(); Loading Loading @@ -10894,6 +10984,10 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") @GuardedBy("mNotificationLock") public void notifyRemovedLocked(NotificationRecord r, int reason, public void notifyRemovedLocked(NotificationRecord r, int reason, NotificationStats notificationStats) { NotificationStats notificationStats) { if (isInLockDownMode()) { return; } final StatusBarNotification sbn = r.getSbn(); final StatusBarNotification sbn = r.getSbn(); // make a copy in case changes are made to the underlying Notification object // make a copy in case changes are made to the underlying Notification object Loading Loading @@ -10939,6 +11033,10 @@ public class NotificationManagerService extends SystemService { */ */ @GuardedBy("mNotificationLock") @GuardedBy("mNotificationLock") public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { if (isInLockDownMode()) { return; } boolean isHiddenRankingUpdate = changedHiddenNotifications != null boolean isHiddenRankingUpdate = changedHiddenNotifications != null && changedHiddenNotifications.size() > 0; && changedHiddenNotifications.size() > 0; // TODO (b/73052211): if the ranking update changed the notification type, // TODO (b/73052211): if the ranking update changed the notification type, Loading services/tests/uiservicestests/AndroidManifest.xml +1 −0 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,7 @@ <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" /> <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" /> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" /> <application android:debuggable="true"> <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> <uses-library android:name="android.test.runner" /> Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +69 −0 Original line number Original line Diff line number Diff line Loading @@ -30,8 +30,11 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.when; Loading @@ -46,6 +49,8 @@ import android.os.Bundle; import android.os.UserHandle; import android.os.UserHandle; import android.service.notification.NotificationListenerFilter; import android.service.notification.NotificationListenerFilter; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; import android.testing.TestableContext; import android.testing.TestableContext; import android.util.ArraySet; import android.util.ArraySet; import android.util.Pair; import android.util.Pair; Loading @@ -59,11 +64,13 @@ import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations; import org.mockito.internal.util.reflection.FieldSetter; import java.io.BufferedInputStream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream; import java.util.List; public class NotificationListenersTest extends UiServiceTestCase { public class NotificationListenersTest extends UiServiceTestCase { Loading Loading @@ -388,4 +395,66 @@ public class NotificationListenersTest extends UiServiceTestCase { verify(mContext).sendBroadcastAsUser( verify(mContext).sendBroadcastAsUser( any(), eq(UserHandle.of(userId)), nullable(String.class)); any(), eq(UserHandle.of(userId)), nullable(String.class)); } } @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(); } @Test public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException { NotificationRecord r = mock(NotificationRecord.class); NotificationStats rs = mock(NotificationStats.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(); } } } Loading
core/api/current.txt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -39069,6 +39069,7 @@ package android.service.notification { field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc field public static final int REASON_LISTENER_CANCEL = 10; // 0xa field public static final int REASON_LISTENER_CANCEL = 10; // 0xa field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb field public static final int REASON_LOCKDOWN = 22; // 0x16 field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
core/java/android/service/notification/NotificationListenerService.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -258,6 +258,8 @@ public abstract class NotificationListenerService extends Service { public static final int REASON_CLEAR_DATA = 21; public static final int REASON_CLEAR_DATA = 21; /** Notification was canceled due to an assistant adjustment update. */ /** Notification was canceled due to an assistant adjustment update. */ public static final int REASON_ASSISTANT_CANCEL = 22; public static final int REASON_ASSISTANT_CANCEL = 22; /** Notification was canceled when lockdown mode is enabled. */ public static final int REASON_LOCKDOWN = 22; /** /** * @hide * @hide Loading Loading @@ -285,6 +287,7 @@ public abstract class NotificationListenerService extends Service { REASON_CHANNEL_REMOVED, REASON_CHANNEL_REMOVED, REASON_CLEAR_DATA, REASON_CLEAR_DATA, REASON_ASSISTANT_CANCEL, REASON_ASSISTANT_CANCEL, REASON_LOCKDOWN, }) }) public @interface NotificationCancelReason{}; public @interface NotificationCancelReason{}; Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +99 −1 Original line number Original line Diff line number Diff line Loading @@ -94,6 +94,7 @@ import static android.service.notification.NotificationListenerService.REASON_ER import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED; import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED; Loading Loading @@ -252,6 +253,7 @@ import android.util.Log; import android.util.Pair; import android.util.Pair; import android.util.Slog; import android.util.Slog; import android.util.SparseArray; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.StatsEvent; import android.util.StatsEvent; import android.util.TypedXmlPullParser; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import android.util.TypedXmlSerializer; Loading Loading @@ -284,6 +286,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.TriPredicate; import com.android.internal.util.function.TriPredicate; import com.android.internal.widget.LockPatternUtils; import com.android.server.DeviceIdleInternal; import com.android.server.DeviceIdleInternal; import com.android.server.EventLogTags; import com.android.server.EventLogTags; import com.android.server.IoThread; import com.android.server.IoThread; Loading Loading @@ -1914,6 +1917,54 @@ public class NotificationManagerService extends SystemService { private SettingsObserver mSettingsObserver; private SettingsObserver mSettingsObserver; protected ZenModeHelper mZenModeHelper; protected ZenModeHelper mZenModeHelper; protected class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker { SparseBooleanArray mUserInLockDownMode = new SparseBooleanArray(); boolean mIsInLockDownMode = false; StrongAuthTracker(Context context) { super(context); } private boolean containsFlag(int haystack, int needle) { return (haystack & needle) != 0; } public boolean isInLockDownMode() { return mIsInLockDownMode; } @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) { return; } if (isInLockDownModeNext) { cancelNotificationsWhenEnterLockDownMode(); } // 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; if (!isInLockDownModeNext) { postNotificationsWhenExitLockDownMode(); } } } private LockPatternUtils mLockPatternUtils; private StrongAuthTracker mStrongAuthTracker; public NotificationManagerService(Context context) { public NotificationManagerService(Context context) { this(context, this(context, new NotificationRecordLoggerImpl(), new NotificationRecordLoggerImpl(), Loading Loading @@ -1942,6 +1993,11 @@ public class NotificationManagerService extends SystemService { mAudioManager = audioMananger; mAudioManager = audioMananger; } } @VisibleForTesting void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) { mStrongAuthTracker = strongAuthTracker; } @VisibleForTesting @VisibleForTesting void setKeyguardManager(KeyguardManager keyguardManager) { void setKeyguardManager(KeyguardManager keyguardManager) { mKeyguardManager = keyguardManager; mKeyguardManager = keyguardManager; Loading Loading @@ -2136,6 +2192,8 @@ public class NotificationManagerService extends SystemService { mPlatformCompat = IPlatformCompat.Stub.asInterface( mPlatformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mLockPatternUtils = new LockPatternUtils(getContext()); mStrongAuthTracker = new StrongAuthTracker(getContext()); mUiHandler = new Handler(UiThread.get().getLooper()); mUiHandler = new Handler(UiThread.get().getLooper()); String[] extractorNames; String[] extractorNames; try { try { Loading Loading @@ -2632,6 +2690,7 @@ public class NotificationManagerService extends SystemService { bubbsExtractor.setShortcutHelper(mShortcutHelper); bubbsExtractor.setShortcutHelper(mShortcutHelper); } } registerNotificationPreferencesPullers(); registerNotificationPreferencesPullers(); mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { // This observer will force an update when observe is called, causing us to // This observer will force an update when observe is called, causing us to // bind to listener services. // bind to listener services. Loading Loading @@ -9528,6 +9587,29 @@ public class NotificationManagerService extends SystemService { } } } } private void cancelNotificationsWhenEnterLockDownMode() { synchronized (mNotificationLock) { int numNotifications = mNotificationList.size(); for (int i = 0; i < numNotifications; i++) { NotificationRecord rec = mNotificationList.get(i); mListeners.notifyRemovedLocked(rec, REASON_LOCKDOWN, rec.getStats()); } } } private void postNotificationsWhenExitLockDownMode() { synchronized (mNotificationLock) { int numNotifications = mNotificationList.size(); for (int i = 0; i < numNotifications; i++) { NotificationRecord rec = mNotificationList.get(i); mListeners.notifyPostedLocked(rec, rec); } } } private void updateNotificationPulse() { private void updateNotificationPulse() { synchronized (mNotificationLock) { synchronized (mNotificationLock) { updateLightsLocked(); updateLightsLocked(); Loading Loading @@ -9744,6 +9826,10 @@ public class NotificationManagerService extends SystemService { rankings.toArray(new NotificationListenerService.Ranking[0])); rankings.toArray(new NotificationListenerService.Ranking[0])); } } boolean isInLockDownMode() { return mStrongAuthTracker.isInLockDownMode(); } boolean hasCompanionDevice(ManagedServiceInfo info) { boolean hasCompanionDevice(ManagedServiceInfo info) { if (mCompanionManager == null) { if (mCompanionManager == null) { mCompanionManager = getCompanionManager(); mCompanionManager = getCompanionManager(); Loading Loading @@ -10795,8 +10881,12 @@ public class NotificationManagerService extends SystemService { * targetting <= O_MR1 * targetting <= O_MR1 */ */ @GuardedBy("mNotificationLock") @GuardedBy("mNotificationLock") private void notifyPostedLocked(NotificationRecord r, NotificationRecord old, void notifyPostedLocked(NotificationRecord r, NotificationRecord old, boolean notifyAllListeners) { boolean notifyAllListeners) { if (isInLockDownMode()) { return; } try { try { // Lazily initialized snapshots of the notification. // Lazily initialized snapshots of the notification. StatusBarNotification sbn = r.getSbn(); StatusBarNotification sbn = r.getSbn(); Loading Loading @@ -10894,6 +10984,10 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") @GuardedBy("mNotificationLock") public void notifyRemovedLocked(NotificationRecord r, int reason, public void notifyRemovedLocked(NotificationRecord r, int reason, NotificationStats notificationStats) { NotificationStats notificationStats) { if (isInLockDownMode()) { return; } final StatusBarNotification sbn = r.getSbn(); final StatusBarNotification sbn = r.getSbn(); // make a copy in case changes are made to the underlying Notification object // make a copy in case changes are made to the underlying Notification object Loading Loading @@ -10939,6 +11033,10 @@ public class NotificationManagerService extends SystemService { */ */ @GuardedBy("mNotificationLock") @GuardedBy("mNotificationLock") public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) { if (isInLockDownMode()) { return; } boolean isHiddenRankingUpdate = changedHiddenNotifications != null boolean isHiddenRankingUpdate = changedHiddenNotifications != null && changedHiddenNotifications.size() > 0; && changedHiddenNotifications.size() > 0; // TODO (b/73052211): if the ranking update changed the notification type, // TODO (b/73052211): if the ranking update changed the notification type, Loading
services/tests/uiservicestests/AndroidManifest.xml +1 −0 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,7 @@ <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" /> <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" /> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" /> <application android:debuggable="true"> <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> <uses-library android:name="android.test.runner" /> Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +69 −0 Original line number Original line Diff line number Diff line Loading @@ -30,8 +30,11 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.when; Loading @@ -46,6 +49,8 @@ import android.os.Bundle; import android.os.UserHandle; import android.os.UserHandle; import android.service.notification.NotificationListenerFilter; import android.service.notification.NotificationListenerFilter; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; import android.testing.TestableContext; import android.testing.TestableContext; import android.util.ArraySet; import android.util.ArraySet; import android.util.Pair; import android.util.Pair; Loading @@ -59,11 +64,13 @@ import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations; import org.mockito.internal.util.reflection.FieldSetter; import java.io.BufferedInputStream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream; import java.util.List; public class NotificationListenersTest extends UiServiceTestCase { public class NotificationListenersTest extends UiServiceTestCase { Loading Loading @@ -388,4 +395,66 @@ public class NotificationListenersTest extends UiServiceTestCase { verify(mContext).sendBroadcastAsUser( verify(mContext).sendBroadcastAsUser( any(), eq(UserHandle.of(userId)), nullable(String.class)); any(), eq(UserHandle.of(userId)), nullable(String.class)); } } @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(); } @Test public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException { NotificationRecord r = mock(NotificationRecord.class); NotificationStats rs = mock(NotificationStats.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(); } } }