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

Commit 83c2beb5 authored by Lucas Silva's avatar Lucas Silva
Browse files

Fix issue where we get stuck in DREAMING state

Occasionally WM may provide an empty or null array of apps to the
unocclude animation runner, which causes it to early exit. The logic
which triggers the transition out of the DREAM state was after that
early exit, causing the device to become stuck in the state. We instead
move that check to before the early exit. The call is a noop if the
device isn't dreaming.

Fixes: 405254417
Test: atest KeyguardViewMediatorTestKt
Flag: EXEMPT bugfix
Change-Id: I90d01e57f1211853a71dea625ae8cf60b377ca21
parent dedeb1e8
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -1340,6 +1340,12 @@ public class KeyguardViewMediator implements CoreStartable,
                                    .setTag("UNOCCLUDE"));
                    setOccluded(false /* isOccluded */, true /* animate */);

                    // This is a noop if we are not currently in the dream state. However, its
                    // important to trigger this here as there may be cases where WM doesn't provide
                    // the apps targets, causing us to early exit below and get stuck in a dreaming
                    // state.
                    mDreamViewModel.get().startTransitionFromDream();

                    if (apps == null || apps.length == 0 || apps[0] == null) {
                        Log.d(TAG, "No apps provided to unocclude runner; "
                                + "skipping animation and unoccluding.");
@@ -1365,9 +1371,7 @@ public class KeyguardViewMediator implements CoreStartable,
                        if (isDream || mShowCommunalWhenUnoccluding) {
                            Log.d(TAG, "Start unocclude animation for dream.");
                            initAlphaForAnimationTargets(wallpapers);
                            if (isDream) {
                                mDreamViewModel.get().startTransitionFromDream();
                            } else {
                            if (!isDream) {
                                mCommunalTransitionViewModel.get().snapToCommunal();
                            }
                            mUnoccludeFinishedCallback = finishedCallback;
+54 −5
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.keyguardUnlockAnimationController
import com.android.keyguard.mediator.ScreenOnCoordinator
import com.android.keyguard.trustManager
import com.android.systemui.Flags
import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.activityTransitionAnimator
import com.android.systemui.broadcast.broadcastDispatcher
@@ -66,21 +66,27 @@ import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.flags.systemPropertiesHelper
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionBootInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.log.sessionTracker
import com.android.systemui.navigationbar.navigationModeController
import com.android.systemui.plugins.statusbar.statusBarStateController
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.process.processWrapper
import com.android.systemui.settings.userTracker
import com.android.systemui.shade.shadeController
import com.android.systemui.statusbar.notificationShadeDepthController
import com.android.systemui.statusbar.notificationShadeWindowController
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.phone.dozeParameters
import com.android.systemui.statusbar.phone.screenOffAnimationController
import com.android.systemui.statusbar.phone.scrimController
@@ -105,6 +111,8 @@ import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever

@@ -115,13 +123,20 @@ import org.mockito.kotlin.whenever
@DisableSceneContainer // Class is deprecated in flexi.
class KeyguardViewMediatorTestKt : SysuiTestCase() {
    private val kosmos =
        testKosmos().useUnconfinedTestDispatcher().also {
            it.powerManager =
        testKosmos().useUnconfinedTestDispatcher().apply {
            powerManager =
                mock<PowerManager> {
                    on { newWakeLock(anyInt(), any()) } doReturn mock<PowerManager.WakeLock>()
                }
            keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy

            val mockViewRootImpl = mock<ViewRootImpl> { on { getView() } doReturn mock<View>() }
            statusBarKeyguardViewManager =
                mock<StatusBarKeyguardViewManager> { on { viewRootImpl } doReturn mockViewRootImpl }
        }

    private val Kosmos.dreamViewModelSpy by Kosmos.Fixture { spy(dreamViewModel) }

    private lateinit var testableLooper: TestableLooper

    private val Kosmos.underTest by
@@ -169,7 +184,7 @@ class KeyguardViewMediatorTestKt : SysuiTestCase() {
                systemClock,
                processWrapper,
                testDispatcher,
                { dreamViewModel },
                { dreamViewModelSpy },
                { communalTransitionViewModel },
                systemPropertiesHelper,
                { mock<WindowManagerLockscreenVisibilityManager>() },
@@ -250,7 +265,41 @@ class KeyguardViewMediatorTestKt : SysuiTestCase() {
        }

    @Test
    @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
    @DisableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR)
    fun unoccludeAnimationRunner_transitionsAwayFromDreamEvenWithEmptyApps() =
        kosmos.runTest {
            setCommunalV2Enabled(false)
            disableHubShowingAutomatically()
            powerInteractor.setAwakeForTest()

            // Given that we are in a dream state.
            fakeKeyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.OFF,
                to = KeyguardState.DREAMING,
                testScope = testScope,
            )

            val apps = emptyArray<RemoteAnimationTarget>()
            val wallpapers = emptyArray<RemoteAnimationTarget>()
            val nonApps = emptyArray<RemoteAnimationTarget>()
            val finishedCallback = mock<IRemoteAnimationFinishedCallback>()

            verify(dreamViewModelSpy, never()).startTransitionFromDream()

            underTest.unoccludeAnimationRunner.onAnimationStart(
                WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE,
                apps,
                wallpapers,
                nonApps,
                finishedCallback,
            )

            verify(finishedCallback).onAnimationFinished()
            verify(dreamViewModelSpy).startTransitionFromDream()
      }

    @Test
    @DisableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR)
    fun unoccludeAnimation_callsFinishedCallback_whenStartedAfterFromDreamingTransitionFinished() =
        kosmos.runTest {
            underTest.onSystemReady()