Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7f339c7 authored by Steve Elliott's avatar Steve Elliott
Browse files

Don't attach private Notification to A11yEvent when user locked

Fixes: 159624555
Test: manual, atest
Change-Id: Ib44f1d3695d2b31bee4f8ccae3f948c83f3b40b6
Merged-In: Ib44f1d3695d2b31bee4f8ccae3f948c83f3b40b6
(cherry picked from commit 54fbccc2)
parent e8f11035
Loading
Loading
Loading
Loading
+28 −7
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.app.IUriGrantsManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -423,6 +424,8 @@ public class NotificationManagerService extends SystemService {
    final ArrayMap<NotificationRecord, ArrayList<CancelNotificationRunnable>> mDelayedCancelations =
            new ArrayMap<>();

    private KeyguardManager mKeyguardManager;

    // The last key in this list owns the hardware.
    ArrayList<String> mLights = new ArrayList<>();

@@ -1465,6 +1468,11 @@ public class NotificationManagerService extends SystemService {
        mAudioManager = audioMananger;
    }

    @VisibleForTesting
    void setKeyguardManager(KeyguardManager keyguardManager) {
        mKeyguardManager = keyguardManager;
    }

    @VisibleForTesting
    void setHints(int hints) {
        mListenerHints = hints;
@@ -1920,6 +1928,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();
            mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class),
                    mPackageManager, getContext().getMainExecutor());
@@ -5790,7 +5799,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?
@@ -5809,7 +5817,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;
        }

@@ -5833,7 +5841,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!");
@@ -6500,17 +6508,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);
        }
+94 −0
Original line number Diff line number Diff line
@@ -44,6 +44,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;
@@ -77,6 +78,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;
@@ -96,6 +98,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
    NotificationUsageStats mUsageStats;
    @Mock
    IAccessibilityManager mAccessibilityService;
    @Mock
    KeyguardManager mKeyguardManager;
    private InjectableSystemClock mSystemClock = new FakeSystemClock();

    private NotificationManagerService mService;
@@ -136,6 +140,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,
@@ -156,6 +161,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
        mService.setFallbackVibrationPattern(FALLBACK_VIBRATION_PATTERN);
        mService.setUsageStats(mUsageStats);
        mService.setAccessibilityManager(accessibilityManager);
        mService.setKeyguardManager(mKeyguardManager);
        mService.mScreenOn = false;
        mService.mInCall = false;
        mService.mNotificationPulseEnabled = true;
@@ -433,6 +439,94 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
        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
    public void testBeepInsistently() throws Exception {
        NotificationRecord r = getInsistentBeepyNotification();