diff options
3 files changed, 175 insertions, 6 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt index dfe56c839283..39aa6152f983 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator +import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background @@ -32,14 +33,21 @@ import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch +@ExperimentalCoroutinesApi @SysUISingleton class FromAlternateBouncerTransitionInteractor @Inject @@ -53,6 +61,7 @@ constructor( private val communalInteractor: CommunalInteractor, powerInteractor: PowerInteractor, keyguardOcclusionInteractor: KeyguardOcclusionInteractor, + private val primaryBouncerInteractor: PrimaryBouncerInteractor, ) : TransitionInteractor( fromState = KeyguardState.ALTERNATE_BOUNCER, @@ -102,13 +111,14 @@ constructor( keyguardInteractor.primaryBouncerShowing, powerInteractor.isAwake, keyguardInteractor.isAodAvailable, - communalInteractor.isIdleOnCommunal + communalInteractor.isIdleOnCommunal, + keyguardInteractor.isKeyguardOccluded, ) .filterRelevantKeyguardStateAnd { (isAlternateBouncerShowing, isPrimaryBouncerShowing, _, _, _) -> !isAlternateBouncerShowing && !isPrimaryBouncerShowing } - .collect { (_, _, isAwake, isAodAvailable, isIdleOnCommunal) -> + .collect { (_, _, isAwake, isAodAvailable, isIdleOnCommunal, isOccluded) -> val to = if (!isAwake) { if (isAodAvailable) { @@ -119,6 +129,8 @@ constructor( } else { if (isIdleOnCommunal) { KeyguardState.GLANCEABLE_HUB + } else if (isOccluded) { + KeyguardState.OCCLUDED } else { KeyguardState.LOCKSCREEN } @@ -135,10 +147,19 @@ constructor( } scope.launch { - keyguardInteractor.isKeyguardGoingAway - .sampleUtil(finishedKeyguardState, ::Pair) - .collect { (isKeyguardGoingAway, keyguardState) -> - if (isKeyguardGoingAway && keyguardState == KeyguardState.ALTERNATE_BOUNCER) { + merge( + keyguardInteractor.isKeyguardGoingAway.filter { it }.map {}, // map to Unit + keyguardInteractor.isKeyguardOccluded.flatMapLatest { keyguardOccluded -> + if (keyguardOccluded) { + primaryBouncerInteractor.keyguardAuthenticatedBiometricsHandled + } else { + emptyFlow() + } + } + ) + .sampleUtil(finishedKeyguardState) + .collect { keyguardState -> + if (keyguardState == KeyguardState.ALTERNATE_BOUNCER) { startTransitionTo(KeyguardState.GONE) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt new file mode 100644 index 000000000000..52bdf0eeb1c6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt @@ -0,0 +1,144 @@ +/* + * 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. + */ + +/* + * 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.bouncer.data.repository.fakeKeyguardBouncerRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat +import com.android.systemui.kosmos.testScope +import com.android.systemui.power.data.repository.fakePowerRepository +import com.android.systemui.power.shared.model.WakeSleepReason +import com.android.systemui.power.shared.model.WakefulnessState +import com.android.systemui.testKosmos +import kotlin.test.Test +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.runner.RunWith +import org.mockito.Mockito +import org.mockito.Mockito.reset + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class FromAlternateBouncerTransitionInteractorTest : SysuiTestCase() { + private val kosmos = + testKosmos().apply { + this.fakeKeyguardTransitionRepository = Mockito.spy(FakeKeyguardTransitionRepository()) + } + private val testScope = kosmos.testScope + private lateinit var underTest: FromAlternateBouncerTransitionInteractor + private lateinit var transitionRepository: FakeKeyguardTransitionRepository + + @Before + fun setup() { + transitionRepository = kosmos.fakeKeyguardTransitionRepository + underTest = kosmos.fromAlternateBouncerTransitionInteractor + underTest.start() + } + + @Test + fun transitionToGone_keyguardOccluded_biometricAuthenticated() = + testScope.runTest { + transitionRepository.sendTransitionSteps( + from = KeyguardState.OCCLUDED, + to = KeyguardState.ALTERNATE_BOUNCER, + testScope + ) + reset(transitionRepository) + + kosmos.fakeKeyguardRepository.setKeyguardOccluded(true) + kosmos.fakeKeyguardBouncerRepository.setKeyguardAuthenticatedBiometrics(true) + runCurrent() + kosmos.fakeKeyguardBouncerRepository.setKeyguardAuthenticatedBiometrics(null) + runCurrent() + + assertThat(transitionRepository) + .startedTransition(from = KeyguardState.ALTERNATE_BOUNCER, to = KeyguardState.GONE) + } + + @Test + fun noTransition_keyguardNotOccluded_biometricAuthenticated() = + testScope.runTest { + transitionRepository.sendTransitionSteps( + from = KeyguardState.OCCLUDED, + to = KeyguardState.ALTERNATE_BOUNCER, + testScope + ) + reset(transitionRepository) + + kosmos.fakeKeyguardRepository.setKeyguardOccluded(false) + kosmos.fakeKeyguardBouncerRepository.setKeyguardAuthenticatedBiometrics(true) + runCurrent() + kosmos.fakeKeyguardBouncerRepository.setKeyguardAuthenticatedBiometrics(null) + runCurrent() + + assertThat(transitionRepository).noTransitionsStarted() + } + + @Test + fun transitionToOccluded() = + testScope.runTest { + kosmos.fakePowerRepository.updateWakefulness( + WakefulnessState.AWAKE, + WakeSleepReason.POWER_BUTTON, + WakeSleepReason.POWER_BUTTON, + false, + ) + kosmos.fakeKeyguardRepository.setKeyguardOccluded(true) + kosmos.fakeKeyguardBouncerRepository.setAlternateVisible(true) + transitionRepository.sendTransitionSteps( + from = KeyguardState.OCCLUDED, + to = KeyguardState.ALTERNATE_BOUNCER, + testScope + ) + reset(transitionRepository) + + kosmos.fakeKeyguardBouncerRepository.setAlternateVisible(false) + runCurrent() + testScope.testScheduler.advanceTimeBy(200) // advance past delay + + assertThat(transitionRepository) + .startedTransition( + from = KeyguardState.ALTERNATE_BOUNCER, + to = KeyguardState.OCCLUDED + ) + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt index 530cbedbdd0c..78a419f92495 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.domain.interactor +import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.kosmos.Kosmos @@ -23,7 +24,9 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor +import kotlinx.coroutines.ExperimentalCoroutinesApi +@ExperimentalCoroutinesApi val Kosmos.fromAlternateBouncerTransitionInteractor by Kosmos.Fixture { FromAlternateBouncerTransitionInteractor( @@ -36,5 +39,6 @@ val Kosmos.fromAlternateBouncerTransitionInteractor by communalInteractor = communalInteractor, powerInteractor = powerInteractor, keyguardOcclusionInteractor = keyguardOcclusionInteractor, + primaryBouncerInteractor = primaryBouncerInteractor, ) } |