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

Commit 285e3a39 authored by Josh Tsuji's avatar Josh Tsuji
Browse files

Add KeyguardLockWhileAwakeInteractor.

This consolidates all logic around GONE -> LOCKSCREEN, and adds support for KeyguardService#doKeyguardTimeout, a method that is called by WM when it wants us to lock while the screen is still on.

Fixes: 365596274
Bug: 278086361
Test: atest KeyguardLockWhileAwakeInteractorTest
Test: test app that calls WM#lockNow, verify we return to lockscreen with flag enabled
Test: user switch from profile with ls disabled to one with ls enabled
Flag: com.android.systemui.keyguard_wm_state_refactor
Change-Id: I874614a68339699a5f6a4d043bdf3e7da7d2ffbd
parent ce3c8280
Loading
Loading
Loading
Loading
+101 −0
Original line number Diff line number Diff line
/*
 * 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 androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
@kotlinx.coroutines.ExperimentalCoroutinesApi
class KeyguardLockWhileAwakeInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private lateinit var underTest: KeyguardLockWhileAwakeInteractor

    @Before
    fun setup() {
        underTest = kosmos.keyguardLockWhileAwakeInteractor
    }

    @Test
    fun emitsMultipleTimeoutEvents() =
        testScope.runTest {
            val values by collectValues(underTest.lockWhileAwakeEvents)

            underTest.onKeyguardServiceDoKeyguardTimeout(options = null)
            runCurrent()

            assertThat(values)
                .containsExactly(LockWhileAwakeReason.KEYGUARD_TIMEOUT_WHILE_SCREEN_ON)

            advanceTimeBy(1000)
            underTest.onKeyguardServiceDoKeyguardTimeout(options = null)
            runCurrent()

            assertThat(values)
                .containsExactly(
                    LockWhileAwakeReason.KEYGUARD_TIMEOUT_WHILE_SCREEN_ON,
                    LockWhileAwakeReason.KEYGUARD_TIMEOUT_WHILE_SCREEN_ON,
                )
        }

    @Test
    fun emitsWhenKeyguardEnabled_onlyIfShowingWhenDisabled() =
        testScope.runTest {
            val values by collectValues(underTest.lockWhileAwakeEvents)

            kosmos.biometricSettingsRepository.setIsUserInLockdown(false)
            runCurrent()

            kosmos.keyguardEnabledInteractor.notifyKeyguardEnabled(false)
            runCurrent()

            assertEquals(0, values.size)

            kosmos.keyguardEnabledInteractor.notifyKeyguardEnabled(true)
            runCurrent()

            assertThat(values).containsExactly(LockWhileAwakeReason.KEYGUARD_REENABLED)

            kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.GONE,
                testScope = testScope,
            )
            kosmos.keyguardEnabledInteractor.notifyKeyguardEnabled(false)
            kosmos.keyguardEnabledInteractor.notifyKeyguardEnabled(true)
            runCurrent()

            assertThat(values).containsExactly(LockWhileAwakeReason.KEYGUARD_REENABLED)
        }
}
+6 −2
Original line number Diff line number Diff line
@@ -560,7 +560,9 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
                .startedTransition(
                    to = KeyguardState.LOCKSCREEN,
                    from = KeyguardState.GONE,
                    ownerName = "FromGoneTransitionInteractor",
                    ownerName =
                        "FromGoneTransitionInteractor" +
                            "(keyguard interactor says keyguard is showing)",
                    animatorAssertion = { it.isNotNull() },
                )

@@ -640,7 +642,9 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
                .startedTransition(
                    to = KeyguardState.GLANCEABLE_HUB,
                    from = KeyguardState.GONE,
                    ownerName = FromGoneTransitionInteractor::class.simpleName,
                    ownerName =
                        FromGoneTransitionInteractor::class.simpleName +
                            "(keyguard interactor says keyguard is showing)",
                    animatorAssertion = { it.isNotNull() },
                )

+11 −1
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardLockWhileAwakeInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardStateCallbackInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardWakeDirectlyToGoneInteractor;
import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier;
@@ -329,6 +330,8 @@ public class KeyguardService extends Service {
            return new FoldGracePeriodProvider();
        }
    };
    private final KeyguardLockWhileAwakeInteractor
            mKeyguardLockWhileAwakeInteractor;

    @Inject
    public KeyguardService(
@@ -353,7 +356,8 @@ public class KeyguardService extends Service {
            KeyguardWakeDirectlyToGoneInteractor keyguardWakeDirectlyToGoneInteractor,
            KeyguardDismissInteractor keyguardDismissInteractor,
            Lazy<DeviceEntryInteractor> deviceEntryInteractorLazy,
            KeyguardStateCallbackInteractor keyguardStateCallbackInteractor) {
            KeyguardStateCallbackInteractor keyguardStateCallbackInteractor,
            KeyguardLockWhileAwakeInteractor keyguardLockWhileAwakeInteractor) {
        super();
        mKeyguardViewMediator = keyguardViewMediator;
        mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
@@ -385,6 +389,7 @@ public class KeyguardService extends Service {
        mKeyguardEnabledInteractor = keyguardEnabledInteractor;
        mKeyguardWakeDirectlyToGoneInteractor = keyguardWakeDirectlyToGoneInteractor;
        mKeyguardDismissInteractor = keyguardDismissInteractor;
        mKeyguardLockWhileAwakeInteractor = keyguardLockWhileAwakeInteractor;
    }

    @Override
@@ -656,6 +661,11 @@ public class KeyguardService extends Service {
        public void doKeyguardTimeout(Bundle options) {
            trace("doKeyguardTimeout");
            checkPermission();

            if (KeyguardWmStateRefactor.isEnabled()) {
                mKeyguardLockWhileAwakeInteractor.onKeyguardServiceDoKeyguardTimeout(options);
            }

            mKeyguardViewMediator.doKeyguardTimeout(options);
        }

+14 −29
Original line number Diff line number Diff line
@@ -24,8 +24,6 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
@@ -54,9 +52,7 @@ constructor(
    powerInteractor: PowerInteractor,
    private val communalSceneInteractor: CommunalSceneInteractor,
    keyguardOcclusionInteractor: KeyguardOcclusionInteractor,
    private val biometricSettingsRepository: BiometricSettingsRepository,
    private val keyguardRepository: KeyguardRepository,
    private val keyguardEnabledInteractor: KeyguardEnabledInteractor,
    private val keyguardLockWhileAwakeInteractor: KeyguardLockWhileAwakeInteractor,
) :
    TransitionInteractor(
        fromState = KeyguardState.GONE,
@@ -78,7 +74,9 @@ constructor(
    }

    fun showKeyguard() {
        scope.launch("$TAG#showKeyguard") { startTransitionTo(KeyguardState.LOCKSCREEN) }
        scope.launch("$TAG#showKeyguard") {
            startTransitionTo(KeyguardState.LOCKSCREEN, ownerReason = "showKeyguard()")
        }
    }

    /**
@@ -102,34 +100,18 @@ constructor(
    // Primarily for when the user chooses to lock down the device
    private fun listenForGoneToLockscreenOrHubOrOccluded() {
        if (KeyguardWmStateRefactor.isEnabled) {
            scope.launch("$TAG#listenForGoneToLockscreenOrHub") {
                biometricSettingsRepository.isCurrentUserInLockdown
                    .distinctUntilChanged()
                    .filterRelevantKeyguardStateAnd { inLockdown -> inLockdown }
            scope.launch {
                keyguardLockWhileAwakeInteractor.lockWhileAwakeEvents
                    .filterRelevantKeyguardState()
                    .sample(communalSceneInteractor.isIdleOnCommunalNotEditMode, ::Pair)
                    .collect { (_, isIdleOnCommunal) ->
                    .collect { (lockReason, idleOnCommunal) ->
                        val to =
                            if (isIdleOnCommunal) {
                            if (idleOnCommunal) {
                                KeyguardState.GLANCEABLE_HUB
                            } else {
                                KeyguardState.LOCKSCREEN
                            }
                        startTransitionTo(to, ownerReason = "User initiated lockdown")
                    }
            }

            scope.launch {
                keyguardRepository.isKeyguardEnabled
                    .filterRelevantKeyguardStateAnd { enabled -> enabled }
                    .sample(keyguardEnabledInteractor.showKeyguardWhenReenabled)
                    .filter { reshow -> reshow }
                    .collect {
                        startTransitionTo(
                            KeyguardState.LOCKSCREEN,
                            ownerReason =
                                "Keyguard was re-enabled, and we weren't GONE when it " +
                                    "was originally disabled",
                        )
                        startTransitionTo(to, ownerReason = "lockWhileAwake: $lockReason")
                    }
            }
        } else {
@@ -146,7 +128,10 @@ constructor(
                            } else {
                                KeyguardState.LOCKSCREEN
                            }
                        startTransitionTo(to)
                        startTransitionTo(
                            to,
                            ownerReason = "keyguard interactor says keyguard is showing",
                        )
                    }
            }
        }
+1 −0
Original line number Diff line number Diff line
@@ -288,6 +288,7 @@ constructor(
                    startTransitionTo(
                        KeyguardState.GONE,
                        modeOnCanceled = TransitionModeOnCanceled.RESET,
                        ownerReason = "keyguard interactor says keyguard is going away",
                    )
                }
        }
Loading