Loading packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt +11 −0 Original line number Diff line number Diff line Loading @@ -25,10 +25,13 @@ import android.view.IRemoteAnimationFinishedCallback import android.view.RemoteAnimationTarget import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardShowWhileAwakeInteractor import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock import com.android.window.flags.Flags Loading Loading @@ -63,6 +66,9 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() { @Mock private lateinit var keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor @Mock private lateinit var keyguardTransitions: KeyguardTransitions @Mock private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var keyguardShowWhileAwakeInteractor: KeyguardShowWhileAwakeInteractor @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor @Before fun setUp() { Loading @@ -77,6 +83,9 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() { keyguardSurfaceBehindAnimator = keyguardSurfaceBehindAnimator, keyguardDismissTransitionInteractor = keyguardDismissTransitionInteractor, keyguardTransitions = keyguardTransitions, selectedUserInteractor = selectedUserInteractor, lockPatternUtils = lockPatternUtils, keyguardShowWhileAwakeInteractor = keyguardShowWhileAwakeInteractor, ) } Loading Loading @@ -236,6 +245,8 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() { .whenever(keyguardDismissTransitionInteractor) .startDismissKeyguardTransition(any(), any()) whenever(selectedUserInteractor.getSelectedUserId()).thenReturn(-1) underTest.onKeyguardGoingAwayRemoteAnimationStart( transit = 0, apps = arrayOf(mock<RemoteAnimationTarget>()), Loading packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +5 −4 Original line number Diff line number Diff line Loading @@ -124,7 +124,6 @@ import com.android.settingslib.Utils; import com.android.settingslib.WirelessUtils; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.systemui.CoreStartable; import com.android.systemui.Dumpable; import com.android.systemui.Flags; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; Loading Loading @@ -301,7 +300,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, CoreSt private final Provider<SceneInteractor> mSceneInteractor; private final Provider<AlternateBouncerInteractor> mAlternateBouncerInteractor; private final Provider<CommunalSceneInteractor> mCommunalSceneInteractor; private final KeyguardServiceShowLockscreenInteractor mKeyguardServiceShowLockscreenInteractor; private final Provider<KeyguardServiceShowLockscreenInteractor> mKeyguardServiceShowLockscreenInteractor; private final AuthController mAuthController; private final UiEventLogger mUiEventLogger; private final Set<String> mAllowFingerprintOnOccludingActivitiesFromPackage; Loading Loading @@ -2219,7 +2219,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, CoreSt Provider<JavaAdapter> javaAdapter, Provider<SceneInteractor> sceneInteractor, Provider<CommunalSceneInteractor> communalSceneInteractor, KeyguardServiceShowLockscreenInteractor keyguardServiceShowLockscreenInteractor) { Provider<KeyguardServiceShowLockscreenInteractor> keyguardServiceShowLockscreenInteractor) { mContext = context; mSubscriptionManager = subscriptionManager; mUserTracker = userTracker; Loading Loading @@ -2553,7 +2554,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, CoreSt if (KeyguardWmStateRefactor.isEnabled()) { mJavaAdapter.get().alwaysCollectFlow( mKeyguardServiceShowLockscreenInteractor.getShowNowEvents(), mKeyguardServiceShowLockscreenInteractor.get().getShowNowEvents(), this::onKeyguardServiceShowLockscreenNowEvents ); } Loading packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +2 −1 Original line number Diff line number Diff line Loading @@ -673,7 +673,8 @@ public class KeyguardService extends Service { if (SceneContainerFlag.isEnabled()) { mDeviceEntryInteractorLazy.get().lockNow("doKeyguardTimeout"); } else if (KeyguardWmStateRefactor.isEnabled()) { mKeyguardServiceShowLockscreenInteractor.onKeyguardServiceDoKeyguardTimeout(); mKeyguardServiceShowLockscreenInteractor .onKeyguardServiceDoKeyguardTimeout(options); } mKeyguardViewMediator.doKeyguardTimeout(options); Loading packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt +52 −4 Original line number Diff line number Diff line Loading @@ -22,11 +22,14 @@ import android.util.Log import android.view.IRemoteAnimationFinishedCallback import android.view.RemoteAnimationTarget import android.view.WindowManager import com.android.internal.widget.LockPatternUtils import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardShowWhileAwakeInteractor import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.window.flags.Flags import com.android.wm.shell.keyguard.KeyguardTransitions import java.util.concurrent.Executor Loading @@ -46,6 +49,9 @@ constructor( private val keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier, private val keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor, private val keyguardTransitions: KeyguardTransitions, private val selectedUserInteractor: SelectedUserInteractor, private val lockPatternUtils: LockPatternUtils, private val keyguardShowWhileAwakeInteractor: KeyguardShowWhileAwakeInteractor, ) { /** Loading Loading @@ -92,12 +98,23 @@ constructor( * second timeout). */ private var isKeyguardGoingAway = false private set(value) { private set(goingAway) { // TODO(b/278086361): Extricate the keyguard state controller. keyguardStateController.notifyKeyguardGoingAway(value) field = value keyguardStateController.notifyKeyguardGoingAway(goingAway) if (goingAway) { keyguardGoingAwayRequestedForUserId = selectedUserInteractor.getSelectedUserId() } field = goingAway } /** * The current user ID when we asked WM to start the keyguard going away animation. This is used * for validation when user switching occurs during unlock. */ private var keyguardGoingAwayRequestedForUserId: Int = -1 /** Callback provided by WM to call once we're done with the going away animation. */ private var goingAwayRemoteAnimationFinishedCallback: IRemoteAnimationFinishedCallback? = null Loading Loading @@ -171,6 +188,14 @@ constructor( nonApps: Array<RemoteAnimationTarget>, finishedCallback: IRemoteAnimationFinishedCallback, ) { goingAwayRemoteAnimationFinishedCallback = finishedCallback if (maybeStartTransitionIfUserSwitchedDuringGoingAway()) { Log.d(TAG, "User switched during keyguard going away - ending remote animation.") endKeyguardGoingAwayAnimation() return } // If we weren't expecting the keyguard to be going away, WM triggered this transition. if (!isKeyguardGoingAway) { // Since WM triggered this, we're likely not transitioning to GONE yet. See if we can Loading Loading @@ -198,7 +223,6 @@ constructor( } if (apps.isNotEmpty()) { goingAwayRemoteAnimationFinishedCallback = finishedCallback keyguardSurfaceBehindAnimator.applyParamsToSurface(apps[0]) } else { // Nothing to do here if we have no apps, end the animation, which will cancel it and WM Loading @@ -211,6 +235,7 @@ constructor( // If WM cancelled the animation, we need to end immediately even if we're still using the // animation. endKeyguardGoingAwayAnimation() maybeStartTransitionIfUserSwitchedDuringGoingAway() } /** Loading Loading @@ -301,6 +326,29 @@ constructor( } } /** * If necessary, start a transition to show/hide keyguard in response to a user switch during * keyguard going away. * * Returns [true] if a transition was started, or false if a transition was not necessary. */ private fun maybeStartTransitionIfUserSwitchedDuringGoingAway(): Boolean { val currentUser = selectedUserInteractor.getSelectedUserId() if (currentUser != keyguardGoingAwayRequestedForUserId) { if (lockPatternUtils.isSecure(currentUser)) { keyguardShowWhileAwakeInteractor.onSwitchedToSecureUserWhileKeyguardGoingAway() } else { keyguardDismissTransitionInteractor.startDismissKeyguardTransition( reason = "User switch during keyguard going away, and new user is insecure" ) } return true } else { return false } } companion object { private val TAG = "WindowManagerLsVis" } Loading packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardServiceShowLockscreenRepository.kt 0 → 100644 +46 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.keyguard.data.repository import android.os.IRemoteCallback import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject /** * Holds an IRemoteCallback along with the current user ID at the time the callback was provided. */ data class ShowLockscreenCallback(val userId: Int, val remoteCallback: IRemoteCallback) /** Maintains state related to KeyguardService requests to show the lockscreen. */ @SysUISingleton class KeyguardServiceShowLockscreenRepository @Inject constructor() { val showLockscreenCallbacks = ArrayList<ShowLockscreenCallback>() /** * Adds a callback that we'll notify when we show the lockscreen (or affirmatively decide not to * show it). */ fun addShowLockscreenCallback(forUser: Int, callback: IRemoteCallback) { synchronized(showLockscreenCallbacks) { showLockscreenCallbacks.add(ShowLockscreenCallback(forUser, callback)) } } companion object { private const val TAG = "ShowLockscreenRepository" } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt +11 −0 Original line number Diff line number Diff line Loading @@ -25,10 +25,13 @@ import android.view.IRemoteAnimationFinishedCallback import android.view.RemoteAnimationTarget import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardShowWhileAwakeInteractor import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock import com.android.window.flags.Flags Loading Loading @@ -63,6 +66,9 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() { @Mock private lateinit var keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor @Mock private lateinit var keyguardTransitions: KeyguardTransitions @Mock private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var keyguardShowWhileAwakeInteractor: KeyguardShowWhileAwakeInteractor @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor @Before fun setUp() { Loading @@ -77,6 +83,9 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() { keyguardSurfaceBehindAnimator = keyguardSurfaceBehindAnimator, keyguardDismissTransitionInteractor = keyguardDismissTransitionInteractor, keyguardTransitions = keyguardTransitions, selectedUserInteractor = selectedUserInteractor, lockPatternUtils = lockPatternUtils, keyguardShowWhileAwakeInteractor = keyguardShowWhileAwakeInteractor, ) } Loading Loading @@ -236,6 +245,8 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() { .whenever(keyguardDismissTransitionInteractor) .startDismissKeyguardTransition(any(), any()) whenever(selectedUserInteractor.getSelectedUserId()).thenReturn(-1) underTest.onKeyguardGoingAwayRemoteAnimationStart( transit = 0, apps = arrayOf(mock<RemoteAnimationTarget>()), Loading
packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +5 −4 Original line number Diff line number Diff line Loading @@ -124,7 +124,6 @@ import com.android.settingslib.Utils; import com.android.settingslib.WirelessUtils; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.systemui.CoreStartable; import com.android.systemui.Dumpable; import com.android.systemui.Flags; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; Loading Loading @@ -301,7 +300,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, CoreSt private final Provider<SceneInteractor> mSceneInteractor; private final Provider<AlternateBouncerInteractor> mAlternateBouncerInteractor; private final Provider<CommunalSceneInteractor> mCommunalSceneInteractor; private final KeyguardServiceShowLockscreenInteractor mKeyguardServiceShowLockscreenInteractor; private final Provider<KeyguardServiceShowLockscreenInteractor> mKeyguardServiceShowLockscreenInteractor; private final AuthController mAuthController; private final UiEventLogger mUiEventLogger; private final Set<String> mAllowFingerprintOnOccludingActivitiesFromPackage; Loading Loading @@ -2219,7 +2219,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, CoreSt Provider<JavaAdapter> javaAdapter, Provider<SceneInteractor> sceneInteractor, Provider<CommunalSceneInteractor> communalSceneInteractor, KeyguardServiceShowLockscreenInteractor keyguardServiceShowLockscreenInteractor) { Provider<KeyguardServiceShowLockscreenInteractor> keyguardServiceShowLockscreenInteractor) { mContext = context; mSubscriptionManager = subscriptionManager; mUserTracker = userTracker; Loading Loading @@ -2553,7 +2554,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, CoreSt if (KeyguardWmStateRefactor.isEnabled()) { mJavaAdapter.get().alwaysCollectFlow( mKeyguardServiceShowLockscreenInteractor.getShowNowEvents(), mKeyguardServiceShowLockscreenInteractor.get().getShowNowEvents(), this::onKeyguardServiceShowLockscreenNowEvents ); } Loading
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +2 −1 Original line number Diff line number Diff line Loading @@ -673,7 +673,8 @@ public class KeyguardService extends Service { if (SceneContainerFlag.isEnabled()) { mDeviceEntryInteractorLazy.get().lockNow("doKeyguardTimeout"); } else if (KeyguardWmStateRefactor.isEnabled()) { mKeyguardServiceShowLockscreenInteractor.onKeyguardServiceDoKeyguardTimeout(); mKeyguardServiceShowLockscreenInteractor .onKeyguardServiceDoKeyguardTimeout(options); } mKeyguardViewMediator.doKeyguardTimeout(options); Loading
packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt +52 −4 Original line number Diff line number Diff line Loading @@ -22,11 +22,14 @@ import android.util.Log import android.view.IRemoteAnimationFinishedCallback import android.view.RemoteAnimationTarget import android.view.WindowManager import com.android.internal.widget.LockPatternUtils import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardShowWhileAwakeInteractor import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.window.flags.Flags import com.android.wm.shell.keyguard.KeyguardTransitions import java.util.concurrent.Executor Loading @@ -46,6 +49,9 @@ constructor( private val keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier, private val keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor, private val keyguardTransitions: KeyguardTransitions, private val selectedUserInteractor: SelectedUserInteractor, private val lockPatternUtils: LockPatternUtils, private val keyguardShowWhileAwakeInteractor: KeyguardShowWhileAwakeInteractor, ) { /** Loading Loading @@ -92,12 +98,23 @@ constructor( * second timeout). */ private var isKeyguardGoingAway = false private set(value) { private set(goingAway) { // TODO(b/278086361): Extricate the keyguard state controller. keyguardStateController.notifyKeyguardGoingAway(value) field = value keyguardStateController.notifyKeyguardGoingAway(goingAway) if (goingAway) { keyguardGoingAwayRequestedForUserId = selectedUserInteractor.getSelectedUserId() } field = goingAway } /** * The current user ID when we asked WM to start the keyguard going away animation. This is used * for validation when user switching occurs during unlock. */ private var keyguardGoingAwayRequestedForUserId: Int = -1 /** Callback provided by WM to call once we're done with the going away animation. */ private var goingAwayRemoteAnimationFinishedCallback: IRemoteAnimationFinishedCallback? = null Loading Loading @@ -171,6 +188,14 @@ constructor( nonApps: Array<RemoteAnimationTarget>, finishedCallback: IRemoteAnimationFinishedCallback, ) { goingAwayRemoteAnimationFinishedCallback = finishedCallback if (maybeStartTransitionIfUserSwitchedDuringGoingAway()) { Log.d(TAG, "User switched during keyguard going away - ending remote animation.") endKeyguardGoingAwayAnimation() return } // If we weren't expecting the keyguard to be going away, WM triggered this transition. if (!isKeyguardGoingAway) { // Since WM triggered this, we're likely not transitioning to GONE yet. See if we can Loading Loading @@ -198,7 +223,6 @@ constructor( } if (apps.isNotEmpty()) { goingAwayRemoteAnimationFinishedCallback = finishedCallback keyguardSurfaceBehindAnimator.applyParamsToSurface(apps[0]) } else { // Nothing to do here if we have no apps, end the animation, which will cancel it and WM Loading @@ -211,6 +235,7 @@ constructor( // If WM cancelled the animation, we need to end immediately even if we're still using the // animation. endKeyguardGoingAwayAnimation() maybeStartTransitionIfUserSwitchedDuringGoingAway() } /** Loading Loading @@ -301,6 +326,29 @@ constructor( } } /** * If necessary, start a transition to show/hide keyguard in response to a user switch during * keyguard going away. * * Returns [true] if a transition was started, or false if a transition was not necessary. */ private fun maybeStartTransitionIfUserSwitchedDuringGoingAway(): Boolean { val currentUser = selectedUserInteractor.getSelectedUserId() if (currentUser != keyguardGoingAwayRequestedForUserId) { if (lockPatternUtils.isSecure(currentUser)) { keyguardShowWhileAwakeInteractor.onSwitchedToSecureUserWhileKeyguardGoingAway() } else { keyguardDismissTransitionInteractor.startDismissKeyguardTransition( reason = "User switch during keyguard going away, and new user is insecure" ) } return true } else { return false } } companion object { private val TAG = "WindowManagerLsVis" } Loading
packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardServiceShowLockscreenRepository.kt 0 → 100644 +46 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.keyguard.data.repository import android.os.IRemoteCallback import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject /** * Holds an IRemoteCallback along with the current user ID at the time the callback was provided. */ data class ShowLockscreenCallback(val userId: Int, val remoteCallback: IRemoteCallback) /** Maintains state related to KeyguardService requests to show the lockscreen. */ @SysUISingleton class KeyguardServiceShowLockscreenRepository @Inject constructor() { val showLockscreenCallbacks = ArrayList<ShowLockscreenCallback>() /** * Adds a callback that we'll notify when we show the lockscreen (or affirmatively decide not to * show it). */ fun addShowLockscreenCallback(forUser: Int, callback: IRemoteCallback) { synchronized(showLockscreenCallbacks) { showLockscreenCallbacks.add(ShowLockscreenCallback(forUser, callback)) } } companion object { private const val TAG = "ShowLockscreenRepository" } }