Don't attach private Notification to A11yEvent when user locked

Fixes: 159624555
Test: manual, atest
Change-Id: Ib44f1d3695d2b31bee4f8ccae3f948c83f3b40b6
This commit is contained in:
Steve Elliott
2021-06-22 13:58:48 -04:00
parent b01c33a788
commit 54fbccc293
2 changed files with 121 additions and 7 deletions

View File

@@ -140,6 +140,7 @@ import android.app.INotificationManager;
import android.app.ITransientNotification; import android.app.ITransientNotification;
import android.app.ITransientNotificationCallback; import android.app.ITransientNotificationCallback;
import android.app.IUriGrantsManager; import android.app.IUriGrantsManager;
import android.app.KeyguardManager;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationChannelGroup; import android.app.NotificationChannelGroup;
@@ -549,6 +550,8 @@ public class NotificationManagerService extends SystemService {
// Used for rate limiting toasts by package. // Used for rate limiting toasts by package.
private MultiRateLimiter mToastRateLimiter; private MultiRateLimiter mToastRateLimiter;
private KeyguardManager mKeyguardManager;
// The last key in this list owns the hardware. // The last key in this list owns the hardware.
ArrayList<String> mLights = new ArrayList<>(); ArrayList<String> mLights = new ArrayList<>();
@@ -2007,6 +2010,11 @@ public class NotificationManagerService extends SystemService {
mAudioManager = audioMananger; mAudioManager = audioMananger;
} }
@VisibleForTesting
void setKeyguardManager(KeyguardManager keyguardManager) {
mKeyguardManager = keyguardManager;
}
@VisibleForTesting @VisibleForTesting
ShortcutHelper getShortcutHelper() { ShortcutHelper getShortcutHelper() {
return mShortcutHelper; return mShortcutHelper;
@@ -2653,6 +2661,7 @@ public class NotificationManagerService extends SystemService {
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = getLocalService(AudioManagerInternal.class); mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mKeyguardManager = getContext().getSystemService(KeyguardManager.class);
mZenModeHelper.onSystemReady(); mZenModeHelper.onSystemReady();
RoleObserver roleObserver = new RoleObserver(getContext(), RoleObserver roleObserver = new RoleObserver(getContext(),
getContext().getSystemService(RoleManager.class), getContext().getSystemService(RoleManager.class),
@@ -7388,7 +7397,6 @@ public class NotificationManagerService extends SystemService {
boolean beep = false; boolean beep = false;
boolean blink = false; boolean blink = false;
final Notification notification = record.getSbn().getNotification();
final String key = record.getKey(); final String key = record.getKey();
// Should this notification make noise, vibe, or use the LED? // Should this notification make noise, vibe, or use the LED?
@@ -7410,7 +7418,7 @@ public class NotificationManagerService extends SystemService {
if (!record.isUpdate if (!record.isUpdate
&& record.getImportance() > IMPORTANCE_MIN && record.getImportance() > IMPORTANCE_MIN
&& !suppressedByDnd) { && !suppressedByDnd) {
sendAccessibilityEvent(notification, record.getSbn().getPackageName()); sendAccessibilityEvent(record);
sentAccessibilityEvent = true; sentAccessibilityEvent = true;
} }
@@ -7433,7 +7441,7 @@ public class NotificationManagerService extends SystemService {
boolean hasAudibleAlert = hasValidSound || hasValidVibrate; boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) { if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
if (!sentAccessibilityEvent) { if (!sentAccessibilityEvent) {
sendAccessibilityEvent(notification, record.getSbn().getPackageName()); sendAccessibilityEvent(record);
sentAccessibilityEvent = true; sentAccessibilityEvent = true;
} }
if (DBG) Slog.v(TAG, "Interrupting!"); if (DBG) Slog.v(TAG, "Interrupting!");
@@ -8261,17 +8269,30 @@ public class NotificationManagerService extends SystemService {
return (x < low) ? low : ((x > high) ? high : x); return (x < low) ? low : ((x > high) ? high : x);
} }
void sendAccessibilityEvent(Notification notification, CharSequence packageName) { void sendAccessibilityEvent(NotificationRecord record) {
if (!mAccessibilityManager.isEnabled()) { if (!mAccessibilityManager.isEnabled()) {
return; return;
} }
AccessibilityEvent event = final Notification notification = record.getNotification();
final CharSequence packageName = record.getSbn().getPackageName();
final AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
event.setPackageName(packageName); event.setPackageName(packageName);
event.setClassName(Notification.class.getName()); event.setClassName(Notification.class.getName());
event.setParcelableData(notification); final int visibilityOverride = record.getPackageVisibilityOverride();
CharSequence tickerText = notification.tickerText; 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);
}
final CharSequence tickerText = notification.tickerText;
if (!TextUtils.isEmpty(tickerText)) { if (!TextUtils.isEmpty(tickerText)) {
event.getText().add(tickerText); event.getText().add(tickerText);
} }

View File

@@ -48,6 +48,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.Notification; import android.app.Notification;
import android.app.Notification.Builder; import android.app.Notification.Builder;
import android.app.NotificationChannel; import android.app.NotificationChannel;
@@ -111,6 +112,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
NotificationUsageStats mUsageStats; NotificationUsageStats mUsageStats;
@Mock @Mock
IAccessibilityManager mAccessibilityService; IAccessibilityManager mAccessibilityService;
@Mock
KeyguardManager mKeyguardManager;
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30); 1 << 30);
@@ -153,6 +156,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
when(mUsageStats.isAlertRateLimited(any())).thenReturn(false); when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
when(mVibrator.hasFrequencyControl()).thenReturn(false); when(mVibrator.hasFrequencyControl()).thenReturn(false);
when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
long serviceReturnValue = IntPair.of( long serviceReturnValue = IntPair.of(
AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED, AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
@@ -174,6 +178,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.setScreenOn(false); mService.setScreenOn(false);
mService.setUsageStats(mUsageStats); mService.setUsageStats(mUsageStats);
mService.setAccessibilityManager(accessibilityManager); mService.setAccessibilityManager(accessibilityManager);
mService.setKeyguardManager(mKeyguardManager);
mService.mScreenOn = false; mService.mScreenOn = false;
mService.mInCallStateOffHook = false; mService.mInCallStateOffHook = false;
mService.mNotificationPulseEnabled = true; mService.mNotificationPulseEnabled = true;
@@ -495,6 +500,94 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
assertNotEquals(-1, r.getLastAudiblyAlertedMs()); assertNotEquals(-1, r.getLastAudiblyAlertedMs());
} }
@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 @Test
public void testBeepInsistently() throws Exception { public void testBeepInsistently() throws Exception {
NotificationRecord r = getInsistentBeepyNotification(); NotificationRecord r = getInsistentBeepyNotification();