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

Commit 24025b16 authored by Grace Cheng's avatar Grace Cheng
Browse files

Updates notifications and media visibility during secure lock device

1) Factors secure lock device enabled state into
KeyguardNotificationVisibilityProvider#userSettingsDisallowNotification,
which determines when notifications should be visible on keyguard.
2) Updates NotificationManagerService.StrongAuthTracker#onStrongAuthRequiredChanged
flow to factor in secure lock device enabled state, which updates
userInLockDownModeNext, which is used to cancel notifications when
entering lockdown and posts notifications on exit from lockdown mode
3) Factors secure lock device enabled state changes into
MediaCarouselController visibility

Flag: android.security.secure_lock_device
Bug: 396641431
Bug: 396680098
Bug: 401645997
Fixes: 400307326
Fixes: 400308016
Test: atest KeyguardNotificationVisibilityProviderTest
Test: atest NotificationManagerServiceTest
Test: atest MediaCarouselControllerTest
Change-Id: I099fe3ee8499ef69af2074e2b40fab95114c601a
parent 56a5da35
Loading
Loading
Loading
Loading
+23 −5
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
import static android.security.Flags.FLAG_SECURE_LOCK_DEVICE;

import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
@@ -56,9 +57,9 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.ambient.statusbar.shared.flag.OngoingActivityChipsOnDream;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.securelockdevice.domain.interactor.SecureLockDeviceInteractor;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
@@ -103,7 +104,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
    @Mock private UserTracker mUserTracker;
    private final FakeSettings mSecureSettings = new FakeSettings();
    private final FakeGlobalSettings mGlobalSettings = new FakeGlobalSettings();
    private final FakeFeatureFlagsClassic mFeatureFlags = new FakeFeatureFlagsClassic();
    private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);

    private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
    private NotificationEntry mEntry;
@@ -125,7 +126,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
                                mUserTracker,
                                mSecureSettings,
                                mGlobalSettings,
                                mFeatureFlags);
                                mKosmos.getSecureLockDeviceInteractor());
        mKeyguardNotificationVisibilityProvider = component.getProvider();
        for (CoreStartable startable : component.getCoreStartables().values()) {
            startable.start();
@@ -461,6 +462,21 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
        assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
    }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    public void secure_lock_device() {
        // GIVEN an 'unfiltered-keyguard-showing' state
        setupUnfilteredState(mEntry);

        // WHEN the notification's user is in secure lock device:
        mKosmos.getFakeSecureLockDeviceRepository().onSecureLockDeviceEnabled();
        mKosmos.getTestDispatcher().getScheduler().runCurrent();

        // THEN filter out the entry
        assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
    }


    @Test
    public void publicMode_settingsDisallow() {
        // GIVEN an 'unfiltered-keyguard-showing' state
@@ -702,6 +718,8 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
        when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
        when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
        when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
        // neither the current user nor the notification's user is in secure lock device
        mKosmos.getFakeSecureLockDeviceRepository().onSecureLockDeviceDisabled();

        // not in public mode
        when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
@@ -745,7 +763,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
                    @BindsInstance UserTracker userTracker,
                    @BindsInstance SecureSettings secureSettings,
                    @BindsInstance GlobalSettings globalSettings,
                    @BindsInstance FeatureFlagsClassic featureFlags
                    @BindsInstance SecureLockDeviceInteractor secureLockDeviceInteractor
            );
        }
    }
+7 −1
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ import com.android.systemui.qs.PageIndicator
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.securelockdevice.domain.interactor.SecureLockDeviceInteractor
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.featurepods.media.domain.interactor.MediaControlChipInteractor
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
@@ -92,6 +93,7 @@ import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import com.android.systemui.util.time.SystemClock
import dagger.Lazy
import java.io.PrintWriter
import java.util.Locale
import java.util.TreeMap
@@ -149,6 +151,7 @@ constructor(
    private val mediaViewControllerFactory: Provider<MediaViewController>,
    private val deviceEntryInteractor: DeviceEntryInteractor,
    private val mediaControlChipInteractor: MediaControlChipInteractor,
    private val secureLockDeviceInteractor: Lazy<SecureLockDeviceInteractor>,
) : Dumpable {
    /** The current width of the carousel */
    var currentCarouselWidth: Int = 0
@@ -299,7 +302,10 @@ constructor(
    private val keyguardUpdateMonitorCallback =
        object : KeyguardUpdateMonitorCallback() {
            override fun onStrongAuthStateChanged(userId: Int) {
                if (keyguardUpdateMonitor.isUserInLockdown(userId)) {
                if (
                    keyguardUpdateMonitor.isUserInLockdown(userId) ||
                        secureLockDeviceInteractor.get().isSecureLockDeviceEnabled.value
                ) {
                    debugLogger.logCarouselHidden()
                    hideMediaCarousel()
                } else if (keyguardUpdateMonitor.isUserUnlocked(userId)) {
+7 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ import android.os.Handler
import android.os.HandlerExecutor
import android.os.UserHandle
import android.provider.Settings
import android.security.Flags.secureLockDevice
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.CoreStartable
@@ -15,6 +16,7 @@ import com.android.systemui.ambient.statusbar.shared.flag.OngoingActivityChipsOn
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.securelockdevice.domain.interactor.SecureLockDeviceInteractor
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
@@ -31,6 +33,7 @@ import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.withIncreasedIndent
import dagger.Binds
import dagger.Lazy
import dagger.Module
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
@@ -84,6 +87,7 @@ constructor(
    private val userTracker: UserTracker,
    private val secureSettings: SecureSettings,
    private val globalSettings: GlobalSettings,
    private val secureLockDeviceInteractor: Lazy<SecureLockDeviceInteractor>,
) : CoreStartable, KeyguardNotificationVisibilityProvider {
    private val showSilentNotifsUri =
        secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS)
@@ -207,6 +211,9 @@ constructor(
            !isLockedOrLocking -> SHOW
            // Notifications not allowed on the lockscreen, always hide.
            !lockscreenUserManager.shouldShowLockscreenNotifications() -> HIDE
            // secure lock device mode is enabled always disallow
            secureLockDevice() &&
                secureLockDeviceInteractor.get().isSecureLockDeviceEnabled.value -> HIDE
            // User settings do not allow this notification on the lockscreen, so hide it.
            userSettingsDisallowNotification(entry) -> HIDE
            // Entry is explicitly marked SECRET, so hide it.
+28 −0
Original line number Diff line number Diff line
@@ -21,7 +21,9 @@ import android.content.res.ColorStateList
import android.content.res.Configuration
import android.database.ContentObserver
import android.os.LocaleList
import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import android.security.Flags.FLAG_SECURE_LOCK_DEVICE
import android.testing.TestableLooper
import android.util.MathUtils.abs
import android.view.View
@@ -61,6 +63,8 @@ import com.android.systemui.scene.data.repository.Idle
import com.android.systemui.scene.data.repository.setSceneTransition
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.securelockdevice.data.repository.fakeSecureLockDeviceRepository
import com.android.systemui.securelockdevice.domain.interactor.secureLockDeviceInteractor
import com.android.systemui.statusbar.featurepods.media.domain.interactor.mediaControlChipInteractor
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
@@ -182,6 +186,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
                mediaViewControllerFactory = mediaViewControllerFactory,
                deviceEntryInteractor = kosmos.deviceEntryInteractor,
                mediaControlChipInteractor = kosmos.mediaControlChipInteractor,
                secureLockDeviceInteractor = { kosmos.secureLockDeviceInteractor },
            )
        verify(configurationController).addCallback(capture(configListener))
        verify(visualStabilityProvider)
@@ -599,6 +604,29 @@ class MediaCarouselControllerTest : SysuiTestCase() {
        verify(mediaCarousel).visibility = View.VISIBLE
    }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    fun testOnSecureLockDeviceMode_hideMediaCarousel() {
        kosmos.fakeSecureLockDeviceRepository.onSecureLockDeviceEnabled()
        mediaCarouselController.mediaCarousel = mediaCarousel

        keyguardCallback.value.onStrongAuthStateChanged(context.userId)

        verify(mediaCarousel).visibility = View.GONE
    }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    fun testOnSecureLockDeviceModeOff_showMediaCarousel() {
        kosmos.fakeSecureLockDeviceRepository.onSecureLockDeviceDisabled()
        whenever(keyguardUpdateMonitor.isUserUnlocked(context.userId)).thenReturn(true)
        mediaCarouselController.mediaCarousel = mediaCarousel

        keyguardCallback.value.onStrongAuthStateChanged(context.userId)

        verify(mediaCarousel).visibility = View.VISIBLE
    }

    @DisableSceneContainer
    @Test
    fun testKeyguardGone_showMediaCarousel() =
+15 −4
Original line number Diff line number Diff line
@@ -115,6 +115,8 @@ import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserHandle.getUserHandleForUid;
import static android.security.Flags.secureLockDevice;
import static android.security.Flags.secureLockdown;
import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
import static android.service.notification.Adjustment.KEY_TYPE;
import static android.service.notification.Adjustment.KEY_UNCLASSIFY;
@@ -411,6 +413,7 @@ import com.android.server.notification.toast.ToastRecord;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.security.authenticationpolicy.SecureLockDeviceServiceInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.Slogf;
@@ -685,6 +688,7 @@ public class NotificationManagerService extends SystemService {
    private PermissionManager mPermissionManager;
    private PermissionPolicyInternal mPermissionPolicyInternal;
    @Nullable private SecureLockDeviceServiceInternal mSecureLockDeviceService;
    // Can be null for wear
    @Nullable StatusBarManagerInternal mStatusBar;
    private DisplayManager mDisplayManager;
@@ -2610,9 +2614,12 @@ public class NotificationManagerService extends SystemService {
        @Override
        public synchronized void onStrongAuthRequiredChanged(int userId) {
            boolean userInSecureLockDevice = false;
            if (secureLockDevice() && mSecureLockDeviceService != null) {
                userInSecureLockDevice = mSecureLockDeviceService.isSecureLockDeviceEnabled();
            }
            boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId),
                    STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
                    STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) || userInSecureLockDevice;
            // Nothing happens if the lockdown mode of userId keeps the same.
            if (userInLockDownModeNext == isInLockDownMode(userId)) {
                return;
@@ -2630,7 +2637,6 @@ public class NotificationManagerService extends SystemService {
            if (userInLockDownModeNext) {
                cancelNotificationsWhenEnterLockDownMode(userId);
            }
            mUserInLockDownMode.put(userId, userInLockDownModeNext);
            if (!userInLockDownModeNext) {
@@ -3480,7 +3486,12 @@ public class NotificationManagerService extends SystemService {
    @VisibleForTesting
    void onBootPhase(int phase, Looper mainLooper) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
        if (phase == SystemService.PHASE_LOCK_SETTINGS_READY) {
            if (secureLockdown()) {
                mSecureLockDeviceService =
                        LocalServices.getService(SecureLockDeviceServiceInternal.class);
            }
        } else if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            mDisplayManager = getContext().getSystemService(DisplayManager.class);
            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
            mZenModeHelper.onSystemReady();
Loading