Loading services/core/java/com/android/server/notification/NotificationManagerService.java 100644 → 100755 +27 −7 Original line number Diff line number Diff line Loading @@ -91,6 +91,7 @@ import android.app.AutomaticZenRule; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; Loading Loading @@ -367,6 +368,8 @@ public class NotificationManagerService extends SystemService { final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>(); private KeyguardManager mKeyguardManager; // The last key in this list owns the hardware. ArrayList<String> mLights = new ArrayList<>(); Loading Loading @@ -1258,6 +1261,10 @@ public class NotificationManagerService extends SystemService { } @VisibleForTesting void setKeyguardManager(KeyguardManager keyguardManager) { mKeyguardManager = keyguardManager; } void setVibrator(Vibrator vibrator) { mVibrator = vibrator; } Loading Loading @@ -1631,6 +1638,7 @@ public class NotificationManagerService extends SystemService { mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManagerInternal = getLocalService(AudioManagerInternal.class); mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mKeyguardManager = getContext().getSystemService(KeyguardManager.class); mZenModeHelper.onSystemReady(); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { // This observer will force an update when observe is called, causing us to Loading Loading @@ -4793,7 +4801,6 @@ public class NotificationManagerService extends SystemService { boolean beep = false; boolean blink = false; final Notification notification = record.sbn.getNotification(); final String key = record.getKey(); // Should this notification make noise, vibe, or use the LED? Loading @@ -4810,7 +4817,7 @@ public class NotificationManagerService extends SystemService { // If the notification will appear in the status bar, it should send an accessibility // event if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) { sendAccessibilityEvent(notification, record.sbn.getPackageName()); sendAccessibilityEvent(record); sentAccessibilityEvent = true; } Loading @@ -4834,7 +4841,7 @@ public class NotificationManagerService extends SystemService { boolean hasAudibleAlert = hasValidSound || hasValidVibrate; if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) { if (!sentAccessibilityEvent) { sendAccessibilityEvent(notification, record.sbn.getPackageName()); sendAccessibilityEvent(record); sentAccessibilityEvent = true; } if (DBG) Slog.v(TAG, "Interrupting!"); Loading Loading @@ -5397,17 +5404,30 @@ public class NotificationManagerService extends SystemService { return (x < low) ? low : ((x > high) ? high : x); } void sendAccessibilityEvent(Notification notification, CharSequence packageName) { void sendAccessibilityEvent(NotificationRecord record) { if (!mAccessibilityManager.isEnabled()) { return; } AccessibilityEvent event = final Notification notification = record.getNotification(); final CharSequence packageName = record.sbn.getPackageName(); final AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); event.setPackageName(packageName); event.setClassName(Notification.class.getName()); final int visibilityOverride = record.getPackageVisibilityOverride(); final int notifVisibility = visibilityOverride == NotificationManager.VISIBILITY_NO_OVERRIDE ? notification.visibility : visibilityOverride; final int userId = record.getUser().getIdentifier(); final boolean needPublic = userId >= 0 && mKeyguardManager.isDeviceLocked(userId); if (needPublic && notifVisibility != Notification.VISIBILITY_PUBLIC) { // Emit the public version if we're on the lockscreen and this notification isn't // publicly visible. event.setParcelableData(notification.publicVersion); } else { event.setParcelableData(notification); CharSequence tickerText = notification.tickerText; } final CharSequence tickerText = notification.tickerText; if (!TextUtils.isEmpty(tickerText)) { event.getText().add(tickerText); } Loading services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +95 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; Loading @@ -40,6 +41,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.KeyguardManager; import android.app.Notification; import android.app.Notification.Builder; import android.app.NotificationChannel; Loading Loading @@ -71,6 +73,7 @@ import com.android.server.lights.Light; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.Mockito; Loading @@ -90,6 +93,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { NotificationUsageStats mUsageStats; @Mock IAccessibilityManager mAccessibilityService; @Mock KeyguardManager mKeyguardManager; private NotificationManagerService mService; private String mPkg = "com.android.server.notification"; Loading Loading @@ -129,6 +134,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); when(mUsageStats.isAlertRateLimited(any())).thenReturn(false); when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false); long serviceReturnValue = IntPair.of( AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED, Loading @@ -149,6 +155,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.setFallbackVibrationPattern(FALLBACK_VIBRATION_PATTERN); mService.setUsageStats(mUsageStats); mService.setAccessibilityManager(accessibilityManager); mService.setKeyguardManager(mKeyguardManager); } // Loading Loading @@ -405,6 +412,94 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { assertTrue(r.isInterruptive()); } @Test public void testLockedPrivateA11yRedaction() throws Exception { NotificationRecord r = getBeepyNotification(); r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE); r.getNotification().visibility = Notification.VISIBILITY_PRIVATE; when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true); AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); when(accessibilityManager.isEnabled()).thenReturn(true); mService.setAccessibilityManager(accessibilityManager); mService.buzzBeepBlinkLocked(r); ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(AccessibilityEvent.class); verify(accessibilityManager, times(1)) .sendAccessibilityEvent(eventCaptor.capture()); AccessibilityEvent event = eventCaptor.getValue(); assertEquals(r.getNotification().publicVersion, event.getParcelableData()); } @Test public void testLockedOverridePrivateA11yRedaction() throws Exception { NotificationRecord r = getBeepyNotification(); r.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE); r.getNotification().visibility = Notification.VISIBILITY_PUBLIC; when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true); AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); when(accessibilityManager.isEnabled()).thenReturn(true); mService.setAccessibilityManager(accessibilityManager); mService.buzzBeepBlinkLocked(r); ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(AccessibilityEvent.class); verify(accessibilityManager, times(1)) .sendAccessibilityEvent(eventCaptor.capture()); AccessibilityEvent event = eventCaptor.getValue(); assertEquals(r.getNotification().publicVersion, event.getParcelableData()); } @Test public void testLockedPublicA11yNoRedaction() throws Exception { NotificationRecord r = getBeepyNotification(); r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE); r.getNotification().visibility = Notification.VISIBILITY_PUBLIC; when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true); AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); when(accessibilityManager.isEnabled()).thenReturn(true); mService.setAccessibilityManager(accessibilityManager); mService.buzzBeepBlinkLocked(r); ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(AccessibilityEvent.class); verify(accessibilityManager, times(1)) .sendAccessibilityEvent(eventCaptor.capture()); AccessibilityEvent event = eventCaptor.getValue(); assertEquals(r.getNotification(), event.getParcelableData()); } @Test public void testUnlockedPrivateA11yNoRedaction() throws Exception { NotificationRecord r = getBeepyNotification(); r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE); r.getNotification().visibility = Notification.VISIBILITY_PRIVATE; when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false); AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); when(accessibilityManager.isEnabled()).thenReturn(true); mService.setAccessibilityManager(accessibilityManager); mService.buzzBeepBlinkLocked(r); ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(AccessibilityEvent.class); verify(accessibilityManager, times(1)) .sendAccessibilityEvent(eventCaptor.capture()); AccessibilityEvent event = eventCaptor.getValue(); assertEquals(r.getNotification(), event.getParcelableData()); } @Test public void testBeepInsistently() throws Exception { NotificationRecord r = getInsistentBeepyNotification(); Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java 100644 → 100755 +27 −7 Original line number Diff line number Diff line Loading @@ -91,6 +91,7 @@ import android.app.AutomaticZenRule; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; Loading Loading @@ -367,6 +368,8 @@ public class NotificationManagerService extends SystemService { final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>(); private KeyguardManager mKeyguardManager; // The last key in this list owns the hardware. ArrayList<String> mLights = new ArrayList<>(); Loading Loading @@ -1258,6 +1261,10 @@ public class NotificationManagerService extends SystemService { } @VisibleForTesting void setKeyguardManager(KeyguardManager keyguardManager) { mKeyguardManager = keyguardManager; } void setVibrator(Vibrator vibrator) { mVibrator = vibrator; } Loading Loading @@ -1631,6 +1638,7 @@ public class NotificationManagerService extends SystemService { mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManagerInternal = getLocalService(AudioManagerInternal.class); mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mKeyguardManager = getContext().getSystemService(KeyguardManager.class); mZenModeHelper.onSystemReady(); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { // This observer will force an update when observe is called, causing us to Loading Loading @@ -4793,7 +4801,6 @@ public class NotificationManagerService extends SystemService { boolean beep = false; boolean blink = false; final Notification notification = record.sbn.getNotification(); final String key = record.getKey(); // Should this notification make noise, vibe, or use the LED? Loading @@ -4810,7 +4817,7 @@ public class NotificationManagerService extends SystemService { // If the notification will appear in the status bar, it should send an accessibility // event if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) { sendAccessibilityEvent(notification, record.sbn.getPackageName()); sendAccessibilityEvent(record); sentAccessibilityEvent = true; } Loading @@ -4834,7 +4841,7 @@ public class NotificationManagerService extends SystemService { boolean hasAudibleAlert = hasValidSound || hasValidVibrate; if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) { if (!sentAccessibilityEvent) { sendAccessibilityEvent(notification, record.sbn.getPackageName()); sendAccessibilityEvent(record); sentAccessibilityEvent = true; } if (DBG) Slog.v(TAG, "Interrupting!"); Loading Loading @@ -5397,17 +5404,30 @@ public class NotificationManagerService extends SystemService { return (x < low) ? low : ((x > high) ? high : x); } void sendAccessibilityEvent(Notification notification, CharSequence packageName) { void sendAccessibilityEvent(NotificationRecord record) { if (!mAccessibilityManager.isEnabled()) { return; } AccessibilityEvent event = final Notification notification = record.getNotification(); final CharSequence packageName = record.sbn.getPackageName(); final AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); event.setPackageName(packageName); event.setClassName(Notification.class.getName()); final int visibilityOverride = record.getPackageVisibilityOverride(); final int notifVisibility = visibilityOverride == NotificationManager.VISIBILITY_NO_OVERRIDE ? notification.visibility : visibilityOverride; final int userId = record.getUser().getIdentifier(); final boolean needPublic = userId >= 0 && mKeyguardManager.isDeviceLocked(userId); if (needPublic && notifVisibility != Notification.VISIBILITY_PUBLIC) { // Emit the public version if we're on the lockscreen and this notification isn't // publicly visible. event.setParcelableData(notification.publicVersion); } else { event.setParcelableData(notification); CharSequence tickerText = notification.tickerText; } final CharSequence tickerText = notification.tickerText; if (!TextUtils.isEmpty(tickerText)) { event.getText().add(tickerText); } Loading
services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +95 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; Loading @@ -40,6 +41,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.KeyguardManager; import android.app.Notification; import android.app.Notification.Builder; import android.app.NotificationChannel; Loading Loading @@ -71,6 +73,7 @@ import com.android.server.lights.Light; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.Mockito; Loading @@ -90,6 +93,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { NotificationUsageStats mUsageStats; @Mock IAccessibilityManager mAccessibilityService; @Mock KeyguardManager mKeyguardManager; private NotificationManagerService mService; private String mPkg = "com.android.server.notification"; Loading Loading @@ -129,6 +134,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); when(mUsageStats.isAlertRateLimited(any())).thenReturn(false); when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false); long serviceReturnValue = IntPair.of( AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED, Loading @@ -149,6 +155,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.setFallbackVibrationPattern(FALLBACK_VIBRATION_PATTERN); mService.setUsageStats(mUsageStats); mService.setAccessibilityManager(accessibilityManager); mService.setKeyguardManager(mKeyguardManager); } // Loading Loading @@ -405,6 +412,94 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { assertTrue(r.isInterruptive()); } @Test public void testLockedPrivateA11yRedaction() throws Exception { NotificationRecord r = getBeepyNotification(); r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE); r.getNotification().visibility = Notification.VISIBILITY_PRIVATE; when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true); AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); when(accessibilityManager.isEnabled()).thenReturn(true); mService.setAccessibilityManager(accessibilityManager); mService.buzzBeepBlinkLocked(r); ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(AccessibilityEvent.class); verify(accessibilityManager, times(1)) .sendAccessibilityEvent(eventCaptor.capture()); AccessibilityEvent event = eventCaptor.getValue(); assertEquals(r.getNotification().publicVersion, event.getParcelableData()); } @Test public void testLockedOverridePrivateA11yRedaction() throws Exception { NotificationRecord r = getBeepyNotification(); r.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE); r.getNotification().visibility = Notification.VISIBILITY_PUBLIC; when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true); AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); when(accessibilityManager.isEnabled()).thenReturn(true); mService.setAccessibilityManager(accessibilityManager); mService.buzzBeepBlinkLocked(r); ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(AccessibilityEvent.class); verify(accessibilityManager, times(1)) .sendAccessibilityEvent(eventCaptor.capture()); AccessibilityEvent event = eventCaptor.getValue(); assertEquals(r.getNotification().publicVersion, event.getParcelableData()); } @Test public void testLockedPublicA11yNoRedaction() throws Exception { NotificationRecord r = getBeepyNotification(); r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE); r.getNotification().visibility = Notification.VISIBILITY_PUBLIC; when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true); AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); when(accessibilityManager.isEnabled()).thenReturn(true); mService.setAccessibilityManager(accessibilityManager); mService.buzzBeepBlinkLocked(r); ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(AccessibilityEvent.class); verify(accessibilityManager, times(1)) .sendAccessibilityEvent(eventCaptor.capture()); AccessibilityEvent event = eventCaptor.getValue(); assertEquals(r.getNotification(), event.getParcelableData()); } @Test public void testUnlockedPrivateA11yNoRedaction() throws Exception { NotificationRecord r = getBeepyNotification(); r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE); r.getNotification().visibility = Notification.VISIBILITY_PRIVATE; when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false); AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); when(accessibilityManager.isEnabled()).thenReturn(true); mService.setAccessibilityManager(accessibilityManager); mService.buzzBeepBlinkLocked(r); ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(AccessibilityEvent.class); verify(accessibilityManager, times(1)) .sendAccessibilityEvent(eventCaptor.capture()); AccessibilityEvent event = eventCaptor.getValue(); assertEquals(r.getNotification(), event.getParcelableData()); } @Test public void testBeepInsistently() throws Exception { NotificationRecord r = getInsistentBeepyNotification(); Loading