diff options
| author | 2024-09-19 16:43:46 -0400 | |
|---|---|---|
| committer | 2024-09-22 22:40:21 -0700 | |
| commit | 09b82637fc73dcb186d91e79845d51be98bc7734 (patch) | |
| tree | 5b68010170fd7ae6af6d6dbe0e3fcc5803dc247f | |
| parent | cddf273f245bee0831155452e95ea9b3208187ca (diff) | |
Tie KeyguardStateCallbackInteractor state to WmLockscreenVisibility + add dismiss callback notifications.
Using KTF state resulted in some showing-state updates coming in just before the WM setLockScreenShown call, which causes issues in tests and also logically doesn't make sense.
Also, whenever we setLockScreenShown(false), notify the dismiss callback registry.
Bug: 278086361
Test: atest KeyguardLockedTests
Flag: com.android.systemui.keyguard_wm_state_refactor
Change-Id: I86b5edfe614a12a84e2722ae73b5d1dd9208cc43
6 files changed, 214 insertions, 35 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractorTest.kt new file mode 100644 index 000000000000..2558d583b001 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractorTest.kt @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2024 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.domain.interactor + +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.internal.policy.IKeyguardDismissCallback +import com.android.internal.policy.IKeyguardStateCallback +import com.android.keyguard.trustManager +import com.android.systemui.Flags +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.dismissCallbackRegistry +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.domain.interactor.keyguardStateCallbackInteractor +import com.android.systemui.testKosmos +import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.time.fakeSystemClock +import kotlin.test.Test +import kotlinx.coroutines.test.currentTime +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito +import org.mockito.Mockito.anyBoolean +import org.mockito.Mockito.anyInt +import org.mockito.kotlin.atLeast +import org.mockito.kotlin.atLeastOnce +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify + +@SmallTest +@RunWith(AndroidJUnit4::class) +class KeyguardStateCallbackInteractorTest : SysuiTestCase() { + + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + + private lateinit var underTest: KeyguardStateCallbackInteractor + private lateinit var callback: IKeyguardStateCallback + private lateinit var systemClock: FakeSystemClock + + @Before + fun setUp() { + systemClock = kosmos.fakeSystemClock + systemClock.setCurrentTimeMillis(testScope.currentTime) + + underTest = kosmos.keyguardStateCallbackInteractor + underTest.start() + + callback = mock<IKeyguardStateCallback>() + } + + @Test + fun test_addCallback_passesInitialValues() = + testScope.runTest { + underTest.addCallback(callback) + + verify(callback).onShowingStateChanged(anyBoolean(), anyInt()) + verify(callback).onInputRestrictedStateChanged(anyBoolean()) + verify(callback).onTrustedChanged(anyBoolean()) + verify(callback).onSimSecureStateChanged(anyBoolean()) + } + + @Test + @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) + fun test_lockscreenVisibility_notifyDismissSucceeded_ifNotVisible() = + testScope.runTest { + underTest.addCallback(callback) + + val dismissCallback = mock<IKeyguardDismissCallback>() + kosmos.dismissCallbackRegistry.addCallback(dismissCallback) + runCurrent() + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GONE, + testScope = testScope, + ) + + systemClock.advanceTime(1) // Required for DismissCallbackRegistry's bgExecutor + verify(dismissCallback).onDismissSucceeded() + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.GONE, + to = KeyguardState.LOCKSCREEN, + testScope = testScope, + ) + + Mockito.verifyNoMoreInteractions(dismissCallback) + } + + @Test + @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) + fun test_lockscreenVisibility_reportsKeyguardShowingChanged() = + testScope.runTest { + underTest.addCallback(callback) + + Mockito.clearInvocations(callback) + Mockito.clearInvocations(kosmos.trustManager) + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GONE, + testScope = testScope, + ) + runCurrent() + + verify(callback, atLeastOnce()).onShowingStateChanged(eq(false), anyInt()) + verify(kosmos.trustManager, atLeastOnce()).reportKeyguardShowingChanged() + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.GONE, + to = KeyguardState.LOCKSCREEN, + testScope = testScope, + ) + + verify(callback, atLeastOnce()).onShowingStateChanged(eq(true), anyInt()) + verify(kosmos.trustManager, atLeast(2)).reportKeyguardShowingChanged() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index ba23eb341b89..0a38ce07a798 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -3314,7 +3314,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, setShowingLocked(false, "onKeyguardExitFinished: " + reason); mWakeAndUnlocking = false; - mDismissCallbackRegistry.notifyDismissSucceeded(); + + if (!KeyguardWmStateRefactor.isEnabled()) { + mDismissCallbackRegistry.notifyDismissSucceeded(); + } + resetKeyguardDonePendingLocked(); mHideAnimationRun = false; adjustStatusBarLocked(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt index 4457f1dfaf09..9b9bdd1bde9b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt @@ -23,12 +23,10 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.DismissCallbackRegistry -import com.android.systemui.keyguard.KeyguardWmStateRefactor import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.keyguard.data.repository.TrustRepository import com.android.systemui.keyguard.shared.model.DismissAction import com.android.systemui.keyguard.shared.model.KeyguardDone -import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.kotlin.Utils.Companion.toQuad @@ -37,7 +35,6 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map @@ -59,7 +56,6 @@ constructor( trustRepository: TrustRepository, alternateBouncerInteractor: AlternateBouncerInteractor, powerInteractor: PowerInteractor, - keyguardTransitionInteractor: KeyguardTransitionInteractor, ) { /* * Updates when a biometric has authenticated the device and is requesting to dismiss @@ -165,14 +161,4 @@ constructor( } } } - - init { - if (KeyguardWmStateRefactor.isEnabled) { - scope.launch { - keyguardTransitionInteractor.currentKeyguardState - .filter { it == KeyguardState.GONE } - .collect { dismissCallbackRegistry.notifyDismissSucceeded() } - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt index 7fd348b8b40e..6fe4ff5122d0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.domain.interactor +import android.app.trust.TrustManager import android.os.DeadObjectException import android.os.RemoteException import com.android.internal.policy.IKeyguardStateCallback @@ -24,6 +25,7 @@ import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.KeyguardWmStateRefactor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.scene.shared.flag.SceneContainerFlag @@ -32,7 +34,6 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -53,6 +54,9 @@ constructor( private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val trustInteractor: TrustInteractor, private val simBouncerInteractor: SimBouncerInteractor, + private val dismissCallbackRegistry: DismissCallbackRegistry, + private val wmLockscreenVisibilityInteractor: WindowManagerLockscreenVisibilityInteractor, + private val trustManager: TrustManager, ) : CoreStartable { private val callbacks = mutableListOf<IKeyguardStateCallback>() @@ -62,28 +66,31 @@ constructor( } applicationScope.launch { - combine( - selectedUserInteractor.selectedUser, - keyguardTransitionInteractor.currentKeyguardState, - keyguardTransitionInteractor.startedKeyguardTransitionStep, - ::Triple, - ) - .collectLatest { (selectedUser, _, _) -> - val iterator = callbacks.iterator() - withContext(backgroundDispatcher) { - while (iterator.hasNext()) { - val callback = iterator.next() - try { - callback.onShowingStateChanged(!isIdleInGone(), selectedUser) - callback.onInputRestrictedStateChanged(!isIdleInGone()) - } catch (e: RemoteException) { - if (e is DeadObjectException) { - iterator.remove() - } + wmLockscreenVisibilityInteractor.lockscreenVisibility.collectLatest { visible -> + val iterator = callbacks.iterator() + withContext(backgroundDispatcher) { + while (iterator.hasNext()) { + val callback = iterator.next() + try { + callback.onShowingStateChanged( + visible, + selectedUserInteractor.getSelectedUserId(), + ) + callback.onInputRestrictedStateChanged(visible) + + trustManager.reportKeyguardShowingChanged() + + if (!visible) { + dismissCallbackRegistry.notifyDismissSucceeded() + } + } catch (e: RemoteException) { + if (e is DeadObjectException) { + iterator.remove() } } } } + } } applicationScope.launch { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt index 52416bae0d9d..ace11573c7c6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt @@ -41,6 +41,5 @@ val Kosmos.keyguardDismissInteractor by trustRepository = trustRepository, alternateBouncerInteractor = alternateBouncerInteractor, powerInteractor = powerInteractor, - keyguardTransitionInteractor = keyguardTransitionInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/KeyguardStateCallbackInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/KeyguardStateCallbackInteractorKosmos.kt new file mode 100644 index 000000000000..58dd522d40ec --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/KeyguardStateCallbackInteractorKosmos.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2024 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.statusbar.domain.interactor + +import com.android.keyguard.trustManager +import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor +import com.android.systemui.keyguard.dismissCallbackRegistry +import com.android.systemui.keyguard.domain.interactor.KeyguardStateCallbackInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.domain.interactor.trustInteractor +import com.android.systemui.keyguard.domain.interactor.windowManagerLockscreenVisibilityInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope +import com.android.systemui.user.domain.interactor.selectedUserInteractor + +val Kosmos.keyguardStateCallbackInteractor by + Kosmos.Fixture { + KeyguardStateCallbackInteractor( + applicationScope = testScope.backgroundScope, + backgroundDispatcher = testDispatcher, + selectedUserInteractor = selectedUserInteractor, + keyguardTransitionInteractor = keyguardTransitionInteractor, + trustInteractor = trustInteractor, + simBouncerInteractor = simBouncerInteractor, + dismissCallbackRegistry = dismissCallbackRegistry, + wmLockscreenVisibilityInteractor = windowManagerLockscreenVisibilityInteractor, + trustManager = trustManager, + ) + } |