1 /*
<lambda>null2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.keyguard.domain.interactor
18 
19 import com.android.systemui.dagger.SysUISingleton
20 import com.android.systemui.dagger.qualifiers.Application
21 import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
22 import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository
23 import com.android.systemui.keyguard.shared.model.Edge
24 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
25 import com.android.systemui.scene.shared.model.Scenes
26 import com.android.systemui.shared.system.ActivityManagerWrapper
27 import com.android.systemui.shared.system.smartspace.SmartspaceState
28 import javax.inject.Inject
29 import kotlinx.coroutines.CoroutineScope
30 import kotlinx.coroutines.flow.SharingStarted
31 import kotlinx.coroutines.flow.StateFlow
32 import kotlinx.coroutines.flow.asStateFlow
33 import kotlinx.coroutines.flow.combine
34 import kotlinx.coroutines.flow.map
35 import kotlinx.coroutines.flow.stateIn
36 
37 @SysUISingleton
38 class InWindowLauncherUnlockAnimationInteractor
39 @Inject
40 constructor(
41     private val repository: InWindowLauncherUnlockAnimationRepository,
42     @Application scope: CoroutineScope,
43     transitionInteractor: KeyguardTransitionInteractor,
44     surfaceBehindRepository: dagger.Lazy<KeyguardSurfaceBehindRepository>,
45     private val activityManager: ActivityManagerWrapper,
46 ) {
47     val startedUnlockAnimation = repository.startedUnlockAnimation.asStateFlow()
48 
49     /**
50      * Whether we've STARTED but not FINISHED a transition to GONE, and the preconditions are met to
51      * play the in-window unlock animation.
52      */
53     val transitioningToGoneWithInWindowAnimation: StateFlow<Boolean> =
54         transitionInteractor
55             .isInTransition(
56                 edge = Edge.create(to = Scenes.Gone),
57                 edgeWithoutSceneContainer = Edge.create(to = GONE)
58             )
59             .map { transitioningToGone -> transitioningToGone && isLauncherUnderneath() }
60             .stateIn(scope, SharingStarted.Eagerly, false)
61 
62     /**
63      * Whether we should start the in-window unlock animation.
64      *
65      * This emits true once the Launcher surface becomes available while we're
66      * [transitioningToGoneWithInWindowAnimation].
67      */
68     val shouldStartInWindowAnimation: StateFlow<Boolean> =
69         combine(
70                 transitioningToGoneWithInWindowAnimation,
71                 surfaceBehindRepository.get().isSurfaceRemoteAnimationTargetAvailable,
72             ) { transitioningWithInWindowAnimation, isSurfaceAvailable ->
73                 transitioningWithInWindowAnimation && isSurfaceAvailable
74             }
75             .stateIn(scope, SharingStarted.Eagerly, false)
76 
77     /** Sets whether we've started */
78     fun setStartedUnlockAnimation(started: Boolean) {
79         repository.setStartedUnlockAnimation(started)
80     }
81 
82     fun setManualUnlockAmount(amount: Float) {
83         repository.setManualUnlockAmount(amount)
84     }
85 
86     fun setLauncherActivityClass(className: String) {
87         repository.setLauncherActivityClass(className)
88     }
89 
90     fun setLauncherSmartspaceState(state: SmartspaceState?) {
91         repository.setLauncherSmartspaceState(state)
92     }
93 
94     /**
95      * Whether the Launcher is currently underneath the lockscreen (it's at the top of the activity
96      * task stack).
97      */
98     fun isLauncherUnderneath(): Boolean {
99         return repository.launcherActivityClass.value?.let {
100             activityManager.runningTask?.topActivity?.className?.equals(it)
101         }
102             ?: false
103     }
104 }
105