Loading packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt +57 −118 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { InWindowLauncherUnlockAnimationInteractor( kosmos.inWindowLauncherUnlockAnimationRepository, kosmos.applicationCoroutineScope, kosmos.applicationCoroutineScope, kosmos.keyguardTransitionInteractor, { kosmos.keyguardSurfaceBehindRepository }, kosmos.activityManagerWrapper, Loading @@ -73,29 +74,24 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { @Test fun testTransitioningToGoneWithInWindowAnimation_trueIfTopActivityIsLauncher_andTransitioningToGone() = testScope.runTest { transitionToGoneThenLockscreen(withLauncherUnderneath = true) val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. false // False by default. ), values ) // Put launcher on top kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName values, ) activityManagerWrapper.mockTopActivityClassName(launcherClassName) runCurrent() // Should still be false since we're not transitioning to GONE. assertEquals( listOf( false, // False by default. false // False by default. ), values values, ) transitionRepository.sendTransitionStep( Loading @@ -112,7 +108,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { false, true, // -> GONE + launcher is behind ), values values, ) activityManagerWrapper.mockTopActivityClassName("not_launcher") Loading @@ -131,7 +127,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { true, // Top activity should be sampled, if it changes midway it should not // matter. ), values values, ) transitionRepository.sendTransitionStep( Loading @@ -149,35 +145,23 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { true, false, // False once we're not transitioning anymore. ), values values, ) } @Test fun testTransitioningToGoneWithInWindowAnimation_falseIfTopActivityIsLauncherPartwayThrough() = testScope.runTest { val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. ), values ) transitionToGoneThenLockscreen(withLauncherUnderneath = false) // Put not launcher on top kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName ) activityManagerWrapper.mockTopActivityClassName("not_launcher") val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation) runCurrent() assertEquals( listOf( false, false // False by default. ), values values, ) transitionRepository.sendTransitionStep( Loading @@ -189,12 +173,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) activityManagerWrapper.mockTopActivityClassName(launcherClassName) transitionRepository.sendTransitionStep( Loading @@ -206,12 +185,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) transitionRepository.sendTransitionStep( TransitionStep( Loading @@ -222,39 +196,21 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) } @Test fun testTransitioningToGoneWithInWindowAnimation_falseIfTopActivityIsLauncherWhileNotTransitioningToGone() = testScope.runTest { transitionToGoneThenLockscreen(withLauncherUnderneath = true) val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. false // False by default. ), values ) // Put launcher on top kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName ) activityManagerWrapper.mockTopActivityClassName(launcherClassName) runCurrent() assertEquals( listOf( false, ), values values, ) transitionRepository.sendTransitionStep( Loading @@ -266,32 +222,24 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) } @Test fun testShouldStartInWindowAnimation_trueOnceSurfaceAvailable_falseWhenTransitionEnds() = testScope.runTest { transitionToGoneThenLockscreen(withLauncherUnderneath = true) val values by collectValues(underTest.shouldStartInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. false // False by default. ), values values, ) // Put Launcher on top and begin transitioning to GONE. kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName ) activityManagerWrapper.mockTopActivityClassName(launcherClassName) transitionRepository.sendTransitionStep( TransitionStep( transitionState = TransitionState.STARTED, Loading @@ -301,12 +249,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) kosmos.keyguardSurfaceBehindRepository.setSurfaceRemoteAnimationTargetAvailable(true) runCurrent() Loading @@ -316,7 +259,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { false, true, // The surface is now available, so we should start the animation. ), values values, ) transitionRepository.sendTransitionStep( Loading @@ -328,34 +271,24 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, true, false, ), values ) assertEquals(listOf(false, true, false), values) } @Test fun testShouldStartInWindowAnimation_neverTrueIfSurfaceNotAvailable() = testScope.runTest { transitionToGoneThenLockscreen(withLauncherUnderneath = true) val values by collectValues(underTest.shouldStartInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. false // False by default. ), values values, ) // Put Launcher on top and begin transitioning to GONE. kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName ) activityManagerWrapper.mockTopActivityClassName(launcherClassName) transitionRepository.sendTransitionStep( TransitionStep( transitionState = TransitionState.STARTED, Loading @@ -372,32 +305,23 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) } @Test fun testShouldStartInWindowAnimation_falseIfSurfaceAvailable_afterTransitionInterrupted() = testScope.runTest { transitionToGoneThenLockscreen(withLauncherUnderneath = true) val values by collectValues(underTest.shouldStartInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. false // False by default. ), values values, ) // Put Launcher on top and begin transitioning to GONE. kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName ) activityManagerWrapper.mockTopActivityClassName(launcherClassName) transitionRepository.sendTransitionStep( TransitionStep( transitionState = TransitionState.STARTED, Loading @@ -422,11 +346,26 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { kosmos.keyguardSurfaceBehindRepository.setSurfaceRemoteAnimationTargetAvailable(true) runCurrent() assertEquals( listOf( false, ), values assertEquals(listOf(false), values) } /** Transitions to GONE from LOCKSCREEN after setting launcher underneath (or not). */ private suspend fun transitionToGoneThenLockscreen(withLauncherUnderneath: Boolean) { transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE, testScope, ) kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(launcherClassName) activityManagerWrapper.mockTopActivityClassName( if (withLauncherUnderneath) launcherClassName else "not_launcher" ) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN, testScope, ) } } packages/SystemUI/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepository.kt +6 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,8 @@ class InWindowLauncherUnlockAnimationRepository @Inject constructor() { */ val launcherSmartspaceState: MutableStateFlow<SmartspaceState?> = MutableStateFlow(null) val isLauncherUnderneath: MutableStateFlow<Boolean> = MutableStateFlow(false) fun setStartedUnlockAnimation(started: Boolean) { startedUnlockAnimation.value = started } Loading @@ -86,4 +88,8 @@ class InWindowLauncherUnlockAnimationRepository @Inject constructor() { fun setLauncherSmartspaceState(state: SmartspaceState?) { launcherSmartspaceState.value = state } fun setIsLauncherUnderneath(isUnderneath: Boolean) { isLauncherUnderneath.value = isUnderneath } } packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractor.kt +40 −6 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.domain.interactor 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.data.repository.InWindowLauncherUnlockAnimationRepository import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository import com.android.systemui.keyguard.shared.model.Edge Loading @@ -31,8 +32,10 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @SysUISingleton class InWindowLauncherUnlockAnimationInteractor Loading @@ -40,6 +43,7 @@ class InWindowLauncherUnlockAnimationInteractor constructor( private val repository: InWindowLauncherUnlockAnimationRepository, @Application scope: CoroutineScope, @Background val backgroundScope: CoroutineScope, transitionInteractor: KeyguardTransitionInteractor, surfaceBehindRepository: dagger.Lazy<KeyguardSurfaceBehindRepository>, private val activityManager: ActivityManagerWrapper, Loading @@ -54,7 +58,7 @@ constructor( transitionInteractor .isInTransition( edge = Edge.create(to = Scenes.Gone), edgeWithoutSceneContainer = Edge.create(to = GONE) edgeWithoutSceneContainer = Edge.create(to = GONE), ) .map { transitioningToGone -> transitioningToGone && isLauncherUnderneath() } .stateIn(scope, SharingStarted.Eagerly, false) Loading @@ -74,6 +78,25 @@ constructor( } .stateIn(scope, SharingStarted.Eagerly, false) init { backgroundScope.launch { // Whenever we're not GONE, update whether Launcher was the app in front. We need to do // this before the next unlock, but it triggers a binder call, so this is the best time // to do it. In edge cases where this changes while we're locked (the foreground app // crashes, etc.) the worst case is that we fall back to the normal unlock animation (or // unnecessarily play the animation on Launcher when there's an app over it), which is // not a big deal. transitionInteractor.currentKeyguardState .map { it != GONE } .distinctUntilChanged() .collect { notOnGone -> if (notOnGone) { updateIsLauncherUnderneath() } } } } /** Sets whether we've started */ fun setStartedUnlockAnimation(started: Boolean) { repository.setStartedUnlockAnimation(started) Loading @@ -92,13 +115,24 @@ constructor( } /** * Whether the Launcher is currently underneath the lockscreen (it's at the top of the activity * task stack). * Whether the Launcher was underneath the lockscreen as of the last time we locked (it's at the * top of the activity task stack). */ fun isLauncherUnderneath(): Boolean { return repository.launcherActivityClass.value?.let { return repository.isLauncherUnderneath.value } /** * Updates whether Launcher is the app underneath the lock screen as of this moment. Triggers a * binder call, so this is run in the background. */ private fun updateIsLauncherUnderneath() { backgroundScope.launch { repository.setIsLauncherUnderneath( repository.launcherActivityClass.value?.let { activityManager.runningTask?.topActivity?.className?.equals(it) } ?: false ) } ?: false } } packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorKosmos.kt +1 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ val Kosmos.inWindowLauncherUnlockAnimationInteractor by InWindowLauncherUnlockAnimationInteractor( repository = inWindowLauncherUnlockAnimationRepository, scope = applicationCoroutineScope, backgroundScope = applicationCoroutineScope, transitionInteractor = keyguardTransitionInteractor, surfaceBehindRepository = Lazy { keyguardSurfaceBehindRepository }, activityManager = activityManagerWrapper, Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt +57 −118 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { InWindowLauncherUnlockAnimationInteractor( kosmos.inWindowLauncherUnlockAnimationRepository, kosmos.applicationCoroutineScope, kosmos.applicationCoroutineScope, kosmos.keyguardTransitionInteractor, { kosmos.keyguardSurfaceBehindRepository }, kosmos.activityManagerWrapper, Loading @@ -73,29 +74,24 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { @Test fun testTransitioningToGoneWithInWindowAnimation_trueIfTopActivityIsLauncher_andTransitioningToGone() = testScope.runTest { transitionToGoneThenLockscreen(withLauncherUnderneath = true) val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. false // False by default. ), values ) // Put launcher on top kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName values, ) activityManagerWrapper.mockTopActivityClassName(launcherClassName) runCurrent() // Should still be false since we're not transitioning to GONE. assertEquals( listOf( false, // False by default. false // False by default. ), values values, ) transitionRepository.sendTransitionStep( Loading @@ -112,7 +108,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { false, true, // -> GONE + launcher is behind ), values values, ) activityManagerWrapper.mockTopActivityClassName("not_launcher") Loading @@ -131,7 +127,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { true, // Top activity should be sampled, if it changes midway it should not // matter. ), values values, ) transitionRepository.sendTransitionStep( Loading @@ -149,35 +145,23 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { true, false, // False once we're not transitioning anymore. ), values values, ) } @Test fun testTransitioningToGoneWithInWindowAnimation_falseIfTopActivityIsLauncherPartwayThrough() = testScope.runTest { val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. ), values ) transitionToGoneThenLockscreen(withLauncherUnderneath = false) // Put not launcher on top kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName ) activityManagerWrapper.mockTopActivityClassName("not_launcher") val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation) runCurrent() assertEquals( listOf( false, false // False by default. ), values values, ) transitionRepository.sendTransitionStep( Loading @@ -189,12 +173,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) activityManagerWrapper.mockTopActivityClassName(launcherClassName) transitionRepository.sendTransitionStep( Loading @@ -206,12 +185,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) transitionRepository.sendTransitionStep( TransitionStep( Loading @@ -222,39 +196,21 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) } @Test fun testTransitioningToGoneWithInWindowAnimation_falseIfTopActivityIsLauncherWhileNotTransitioningToGone() = testScope.runTest { transitionToGoneThenLockscreen(withLauncherUnderneath = true) val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. false // False by default. ), values ) // Put launcher on top kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName ) activityManagerWrapper.mockTopActivityClassName(launcherClassName) runCurrent() assertEquals( listOf( false, ), values values, ) transitionRepository.sendTransitionStep( Loading @@ -266,32 +222,24 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) } @Test fun testShouldStartInWindowAnimation_trueOnceSurfaceAvailable_falseWhenTransitionEnds() = testScope.runTest { transitionToGoneThenLockscreen(withLauncherUnderneath = true) val values by collectValues(underTest.shouldStartInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. false // False by default. ), values values, ) // Put Launcher on top and begin transitioning to GONE. kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName ) activityManagerWrapper.mockTopActivityClassName(launcherClassName) transitionRepository.sendTransitionStep( TransitionStep( transitionState = TransitionState.STARTED, Loading @@ -301,12 +249,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) kosmos.keyguardSurfaceBehindRepository.setSurfaceRemoteAnimationTargetAvailable(true) runCurrent() Loading @@ -316,7 +259,7 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { false, true, // The surface is now available, so we should start the animation. ), values values, ) transitionRepository.sendTransitionStep( Loading @@ -328,34 +271,24 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, true, false, ), values ) assertEquals(listOf(false, true, false), values) } @Test fun testShouldStartInWindowAnimation_neverTrueIfSurfaceNotAvailable() = testScope.runTest { transitionToGoneThenLockscreen(withLauncherUnderneath = true) val values by collectValues(underTest.shouldStartInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. false // False by default. ), values values, ) // Put Launcher on top and begin transitioning to GONE. kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName ) activityManagerWrapper.mockTopActivityClassName(launcherClassName) transitionRepository.sendTransitionStep( TransitionStep( transitionState = TransitionState.STARTED, Loading @@ -372,32 +305,23 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { ) runCurrent() assertEquals( listOf( false, ), values ) assertEquals(listOf(false), values) } @Test fun testShouldStartInWindowAnimation_falseIfSurfaceAvailable_afterTransitionInterrupted() = testScope.runTest { transitionToGoneThenLockscreen(withLauncherUnderneath = true) val values by collectValues(underTest.shouldStartInWindowAnimation) runCurrent() assertEquals( listOf( false, // False by default. false // False by default. ), values values, ) // Put Launcher on top and begin transitioning to GONE. kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass( launcherClassName ) activityManagerWrapper.mockTopActivityClassName(launcherClassName) transitionRepository.sendTransitionStep( TransitionStep( transitionState = TransitionState.STARTED, Loading @@ -422,11 +346,26 @@ class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() { kosmos.keyguardSurfaceBehindRepository.setSurfaceRemoteAnimationTargetAvailable(true) runCurrent() assertEquals( listOf( false, ), values assertEquals(listOf(false), values) } /** Transitions to GONE from LOCKSCREEN after setting launcher underneath (or not). */ private suspend fun transitionToGoneThenLockscreen(withLauncherUnderneath: Boolean) { transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE, testScope, ) kosmos.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(launcherClassName) activityManagerWrapper.mockTopActivityClassName( if (withLauncherUnderneath) launcherClassName else "not_launcher" ) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN, testScope, ) } }
packages/SystemUI/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepository.kt +6 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,8 @@ class InWindowLauncherUnlockAnimationRepository @Inject constructor() { */ val launcherSmartspaceState: MutableStateFlow<SmartspaceState?> = MutableStateFlow(null) val isLauncherUnderneath: MutableStateFlow<Boolean> = MutableStateFlow(false) fun setStartedUnlockAnimation(started: Boolean) { startedUnlockAnimation.value = started } Loading @@ -86,4 +88,8 @@ class InWindowLauncherUnlockAnimationRepository @Inject constructor() { fun setLauncherSmartspaceState(state: SmartspaceState?) { launcherSmartspaceState.value = state } fun setIsLauncherUnderneath(isUnderneath: Boolean) { isLauncherUnderneath.value = isUnderneath } }
packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractor.kt +40 −6 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.domain.interactor 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.data.repository.InWindowLauncherUnlockAnimationRepository import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository import com.android.systemui.keyguard.shared.model.Edge Loading @@ -31,8 +32,10 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @SysUISingleton class InWindowLauncherUnlockAnimationInteractor Loading @@ -40,6 +43,7 @@ class InWindowLauncherUnlockAnimationInteractor constructor( private val repository: InWindowLauncherUnlockAnimationRepository, @Application scope: CoroutineScope, @Background val backgroundScope: CoroutineScope, transitionInteractor: KeyguardTransitionInteractor, surfaceBehindRepository: dagger.Lazy<KeyguardSurfaceBehindRepository>, private val activityManager: ActivityManagerWrapper, Loading @@ -54,7 +58,7 @@ constructor( transitionInteractor .isInTransition( edge = Edge.create(to = Scenes.Gone), edgeWithoutSceneContainer = Edge.create(to = GONE) edgeWithoutSceneContainer = Edge.create(to = GONE), ) .map { transitioningToGone -> transitioningToGone && isLauncherUnderneath() } .stateIn(scope, SharingStarted.Eagerly, false) Loading @@ -74,6 +78,25 @@ constructor( } .stateIn(scope, SharingStarted.Eagerly, false) init { backgroundScope.launch { // Whenever we're not GONE, update whether Launcher was the app in front. We need to do // this before the next unlock, but it triggers a binder call, so this is the best time // to do it. In edge cases where this changes while we're locked (the foreground app // crashes, etc.) the worst case is that we fall back to the normal unlock animation (or // unnecessarily play the animation on Launcher when there's an app over it), which is // not a big deal. transitionInteractor.currentKeyguardState .map { it != GONE } .distinctUntilChanged() .collect { notOnGone -> if (notOnGone) { updateIsLauncherUnderneath() } } } } /** Sets whether we've started */ fun setStartedUnlockAnimation(started: Boolean) { repository.setStartedUnlockAnimation(started) Loading @@ -92,13 +115,24 @@ constructor( } /** * Whether the Launcher is currently underneath the lockscreen (it's at the top of the activity * task stack). * Whether the Launcher was underneath the lockscreen as of the last time we locked (it's at the * top of the activity task stack). */ fun isLauncherUnderneath(): Boolean { return repository.launcherActivityClass.value?.let { return repository.isLauncherUnderneath.value } /** * Updates whether Launcher is the app underneath the lock screen as of this moment. Triggers a * binder call, so this is run in the background. */ private fun updateIsLauncherUnderneath() { backgroundScope.launch { repository.setIsLauncherUnderneath( repository.launcherActivityClass.value?.let { activityManager.runningTask?.topActivity?.className?.equals(it) } ?: false ) } ?: false } }
packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorKosmos.kt +1 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ val Kosmos.inWindowLauncherUnlockAnimationInteractor by InWindowLauncherUnlockAnimationInteractor( repository = inWindowLauncherUnlockAnimationRepository, scope = applicationCoroutineScope, backgroundScope = applicationCoroutineScope, transitionInteractor = keyguardTransitionInteractor, surfaceBehindRepository = Lazy { keyguardSurfaceBehindRepository }, activityManager = activityManagerWrapper, Loading