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

Commit 8772be29 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Suppress notifications when device enter lockdown"

parents 4811ba19 3cb6842a
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -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
+3 −0
Original line number Original line Diff line number Diff line
@@ -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
@@ -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{};


+99 −1
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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(),
@@ -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;
@@ -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 {
@@ -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.
@@ -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();
@@ -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();
@@ -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();
@@ -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
@@ -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,
+1 −0
Original line number Original line Diff line number Diff line
@@ -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" />
+69 −0
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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;
@@ -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 {


@@ -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