diff options
| author | 2024-05-07 17:45:06 +0000 | |
|---|---|---|
| committer | 2024-05-07 17:45:06 +0000 | |
| commit | 0cb8c7fce882ff779040242e72a9e432548a3dd7 (patch) | |
| tree | d0beb034aca1ebcf2300402daf37ac9a7e3fd475 | |
| parent | d24e1edfc6863008beeb550460dec86c2a2cd9f3 (diff) | |
| parent | 7c450c4abff167b6d74a9b2b445e01f01358eae4 (diff) | |
Merge "Add KeyguardTransitionBootInteractor." into main
8 files changed, 229 insertions, 39 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt index 412292554e73..bf0939c6c46f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt @@ -235,7 +235,13 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { .isEqualTo( listOf( // The initial transition will also get sent when collect started - TransitionStep(OFF, LOCKSCREEN, 0f, STARTED), + TransitionStep( + OFF, + LOCKSCREEN, + 0f, + STARTED, + ownerName = "KeyguardTransitionRepository(boot)" + ), steps[0], steps[3], steps[6] diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt index 662974dd2c91..d079a954cb57 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt @@ -240,6 +240,15 @@ constructor( } /** + * Whether the lockscreen is enabled for the current user. This is `true` whenever the user has + * chosen any secure authentication method and even if they set the lockscreen to be dismissed + * when the user swipes on it. + */ + suspend fun isLockscreenEnabled(): Boolean { + return repository.isLockscreenEnabled() + } + + /** * Whether lockscreen bypass is enabled. When enabled, the lockscreen will be automatically * dismissed once the authentication challenge is completed. For example, completing a biometric * authentication challenge via face unlock or fingerprint sensor can automatically bypass the diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt index 4c54bfd3a17c..e32bfcf81fe2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt @@ -89,6 +89,12 @@ interface KeyguardTransitionRepository { suspend fun startTransition(info: TransitionInfo): UUID? /** + * Emits STARTED and FINISHED transition steps to the given state. This is used during boot to + * seed the repository with the appropriate initial state. + */ + suspend fun emitInitialStepsFromOff(to: KeyguardState) + + /** * Allows manual control of a transition. When calling [startTransition], the consumer must pass * in a null animator. In return, it will get a unique [UUID] that will be validated to allow * further updates. @@ -141,9 +147,17 @@ constructor( private var updateTransitionId: UUID? = null init { - // Seed with transitions signaling a boot into lockscreen state. If updating this, please - // also update FakeKeyguardTransitionRepository. - initialTransitionSteps.forEach(::emitTransition) + // Start with a FINISHED transition in OFF. KeyguardBootInteractor will transition from OFF + // to either GONE or LOCKSCREEN once we're booted up and can determine which state we should + // start in. + emitTransition( + TransitionStep( + KeyguardState.OFF, + KeyguardState.OFF, + 1f, + TransitionState.FINISHED, + ) + ) } override suspend fun startTransition(info: TransitionInfo): UUID? { @@ -251,6 +265,28 @@ constructor( lastStep = nextStep } + override suspend fun emitInitialStepsFromOff(to: KeyguardState) { + emitTransition( + TransitionStep( + KeyguardState.OFF, + to, + 0f, + TransitionState.STARTED, + ownerName = "KeyguardTransitionRepository(boot)", + ) + ) + + emitTransition( + TransitionStep( + KeyguardState.OFF, + to, + 1f, + TransitionState.FINISHED, + ownerName = "KeyguardTransitionRepository(boot)", + ), + ) + } + private fun logAndTrace(step: TransitionStep, isManual: Boolean) { if (step.transitionState == TransitionState.RUNNING) { return @@ -271,31 +307,5 @@ constructor( companion object { private const val TAG = "KeyguardTransitionRepository" - - /** - * Transition steps to seed the repository with, so that all of the transition interactor - * flows emit reasonable initial values. - */ - val initialTransitionSteps: List<TransitionStep> = - listOf( - TransitionStep( - KeyguardState.OFF, - KeyguardState.OFF, - 1f, - TransitionState.FINISHED, - ), - TransitionStep( - KeyguardState.OFF, - KeyguardState.LOCKSCREEN, - 0f, - TransitionState.STARTED, - ), - TransitionStep( - KeyguardState.OFF, - KeyguardState.LOCKSCREEN, - 1f, - TransitionState.FINISHED, - ), - ) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt index 2eeb3b947a11..115fc3610ac8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt @@ -66,7 +66,7 @@ constructor( listenForTransitionToCamera(scope, keyguardInteractor) } - private val canDismissLockScreen: Flow<Boolean> = + private val canTransitionToGoneOnWake: Flow<Boolean> = combine( keyguardInteractor.isKeyguardShowing, keyguardInteractor.isKeyguardDismissible, @@ -87,7 +87,7 @@ constructor( keyguardInteractor.biometricUnlockState, keyguardInteractor.isKeyguardOccluded, communalInteractor.isIdleOnCommunal, - canDismissLockScreen, + canTransitionToGoneOnWake, keyguardInteractor.primaryBouncerShowing, ) .collect { @@ -96,12 +96,12 @@ constructor( biometricUnlockState, occluded, isIdleOnCommunal, - canDismissLockScreen, + canTransitionToGoneOnWake, primaryBouncerShowing) -> startTransitionTo( if (isWakeAndUnlock(biometricUnlockState.mode)) { KeyguardState.GONE - } else if (canDismissLockScreen) { + } else if (canTransitionToGoneOnWake) { KeyguardState.GONE } else if (primaryBouncerShowing) { KeyguardState.PRIMARY_BOUNCER @@ -129,7 +129,7 @@ constructor( .sample( communalInteractor.isIdleOnCommunal, keyguardInteractor.biometricUnlockState, - canDismissLockScreen, + canTransitionToGoneOnWake, keyguardInteractor.primaryBouncerShowing, ) .collect { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt new file mode 100644 index 000000000000..5ad7762bb512 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt @@ -0,0 +1,81 @@ +/* + * 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.util.Log +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor +import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch + +/** Handles initialization of the KeyguardTransitionRepository on boot. */ +@SysUISingleton +class KeyguardTransitionBootInteractor +@Inject +constructor( + @Application val scope: CoroutineScope, + val deviceEntryInteractor: DeviceEntryInteractor, + val deviceProvisioningInteractor: DeviceProvisioningInteractor, + val keyguardTransitionInteractor: KeyguardTransitionInteractor, + val repository: KeyguardTransitionRepository, +) : CoreStartable { + + /** + * Whether the lockscreen should be showing when the device starts up for the first time. If not + * then we'll seed the repository with a transition from OFF -> GONE. + */ + @OptIn(ExperimentalCoroutinesApi::class) + private val showLockscreenOnBoot = + deviceProvisioningInteractor.isDeviceProvisioned.map { provisioned -> + (provisioned || deviceEntryInteractor.isAuthenticationRequired()) && + deviceEntryInteractor.isLockscreenEnabled() + } + + override fun start() { + scope.launch { + val state = + if (showLockscreenOnBoot.first()) { + KeyguardState.LOCKSCREEN + } else { + KeyguardState.GONE + } + + if ( + keyguardTransitionInteractor.currentTransitionInfoInternal.value.from != + KeyguardState.OFF + ) { + Log.e( + "KeyguardTransitionInteractor", + "showLockscreenOnBoot emitted, but we've already " + + "transitioned to a state other than OFF. We'll respect that " + + "transition, but this should not happen." + ) + } else { + repository.emitInitialStepsFromOff(state) + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt index 91f8420393e1..31b0bf7fe425 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt @@ -27,6 +27,7 @@ class KeyguardTransitionCoreStartable constructor( private val interactors: Set<TransitionInteractor>, private val auditLogger: KeyguardTransitionAuditLogger, + private val bootInteractor: KeyguardTransitionBootInteractor, ) : CoreStartable { override fun start() { @@ -51,6 +52,7 @@ constructor( it.start() } auditLogger.start() + bootInteractor.start() } companion object { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt index a242368d1ee1..2fe7438bcc77 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt @@ -40,12 +40,21 @@ import kotlinx.coroutines.test.TestCoroutineScheduler import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent -/** Fake implementation of [KeyguardTransitionRepository] */ +/** + * Fake implementation of [KeyguardTransitionRepository]. + * + * By default, will be seeded with a transition from OFF -> LOCKSCREEN, which is the most common + * case. If the lockscreen is disabled, or we're in setup wizard, the repository will initialize + * with OFF -> GONE. Construct with initInLockscreen = false if your test requires this behavior. + */ @SysUISingleton -class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitionRepository { +class FakeKeyguardTransitionRepository( + private val initInLockscreen: Boolean = true, +) : KeyguardTransitionRepository { private val _transitions = MutableSharedFlow<TransitionStep>(replay = 3, onBufferOverflow = BufferOverflow.DROP_OLDEST) override val transitions: SharedFlow<TransitionStep> = _transitions + @Inject constructor() : this(initInLockscreen = true) private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> = MutableStateFlow( @@ -59,8 +68,21 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio override var currentTransitionInfoInternal = _currentTransitionInfo.asStateFlow() init { - // Seed the fake repository with the same initial steps the actual repository uses. - KeyguardTransitionRepositoryImpl.initialTransitionSteps.forEach { _transitions.tryEmit(it) } + // Seed with a FINISHED transition in OFF, same as the real repository. + _transitions.tryEmit( + TransitionStep( + KeyguardState.OFF, + KeyguardState.OFF, + 1f, + TransitionState.FINISHED, + ) + ) + + if (initInLockscreen) { + tryEmitInitialStepsFromOff(KeyguardState.LOCKSCREEN) + } else { + tryEmitInitialStepsFromOff(KeyguardState.OFF) + } } /** @@ -223,6 +245,32 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio return if (info.animator == null) UUID.randomUUID() else null } + override suspend fun emitInitialStepsFromOff(to: KeyguardState) { + tryEmitInitialStepsFromOff(to) + } + + private fun tryEmitInitialStepsFromOff(to: KeyguardState) { + _transitions.tryEmit( + TransitionStep( + KeyguardState.OFF, + to, + 0f, + TransitionState.STARTED, + ownerName = "KeyguardTransitionRepository(boot)", + ) + ) + + _transitions.tryEmit( + TransitionStep( + KeyguardState.OFF, + to, + 1f, + TransitionState.FINISHED, + ownerName = "KeyguardTransitionRepository(boot)", + ), + ) + } + override fun updateTransition( transitionId: UUID, @FloatRange(from = 0.0, to = 1.0) value: Float, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractorKosmos.kt new file mode 100644 index 000000000000..7d8d33f7dd11 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractorKosmos.kt @@ -0,0 +1,34 @@ +/* + * 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 com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor +import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor + +val Kosmos.keyguardTransitionBootInteractor: KeyguardTransitionBootInteractor by + Kosmos.Fixture { + KeyguardTransitionBootInteractor( + scope = applicationCoroutineScope, + deviceEntryInteractor = deviceEntryInteractor, + deviceProvisioningInteractor = deviceProvisioningInteractor, + keyguardTransitionInteractor = keyguardTransitionInteractor, + repository = keyguardTransitionRepository, + ) + } |