1 /*
<lambda>null2  * Copyright (C) 2022 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 android.animation.ValueAnimator
20 import com.android.app.animation.Interpolators
21 import com.android.app.tracing.coroutines.launch
22 import com.android.systemui.communal.domain.interactor.CommunalInteractor
23 import com.android.systemui.dagger.SysUISingleton
24 import com.android.systemui.dagger.qualifiers.Background
25 import com.android.systemui.dagger.qualifiers.Main
26 import com.android.systemui.keyguard.KeyguardWmStateRefactor
27 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
28 import com.android.systemui.keyguard.data.repository.KeyguardRepository
29 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
30 import com.android.systemui.keyguard.shared.model.KeyguardState
31 import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
32 import com.android.systemui.power.domain.interactor.PowerInteractor
33 import com.android.systemui.scene.shared.flag.SceneContainerFlag
34 import com.android.systemui.util.kotlin.sample
35 import javax.inject.Inject
36 import kotlin.time.Duration.Companion.milliseconds
37 import kotlinx.coroutines.CoroutineDispatcher
38 import kotlinx.coroutines.CoroutineScope
39 import kotlinx.coroutines.flow.distinctUntilChanged
40 import kotlinx.coroutines.flow.filter
41 import kotlinx.coroutines.launch
42 
43 @SysUISingleton
44 class FromGoneTransitionInteractor
45 @Inject
46 constructor(
47     override val transitionRepository: KeyguardTransitionRepository,
48     transitionInteractor: KeyguardTransitionInteractor,
49     @Background private val scope: CoroutineScope,
50     @Background bgDispatcher: CoroutineDispatcher,
51     @Main mainDispatcher: CoroutineDispatcher,
52     keyguardInteractor: KeyguardInteractor,
53     powerInteractor: PowerInteractor,
54     private val communalInteractor: CommunalInteractor,
55     keyguardOcclusionInteractor: KeyguardOcclusionInteractor,
56     private val biometricSettingsRepository: BiometricSettingsRepository,
57     private val keyguardRepository: KeyguardRepository,
58     private val keyguardEnabledInteractor: KeyguardEnabledInteractor,
59 ) :
60     TransitionInteractor(
61         fromState = KeyguardState.GONE,
62         transitionInteractor = transitionInteractor,
63         mainDispatcher = mainDispatcher,
64         bgDispatcher = bgDispatcher,
65         powerInteractor = powerInteractor,
66         keyguardOcclusionInteractor = keyguardOcclusionInteractor,
67         keyguardInteractor = keyguardInteractor,
68     ) {
69 
70     override fun start() {
71         // TODO(b/336576536): Check if adaptation for scene framework is needed
72         if (SceneContainerFlag.isEnabled) return
73         listenForGoneToAodOrDozing()
74         listenForGoneToDreaming()
75         listenForGoneToLockscreenOrHub()
76         listenForGoneToDreamingLockscreenHosted()
77     }
78 
79     fun showKeyguard() {
80         scope.launch("$TAG#showKeyguard") { startTransitionTo(KeyguardState.LOCKSCREEN) }
81     }
82 
83     // Primarily for when the user chooses to lock down the device
84     private fun listenForGoneToLockscreenOrHub() {
85         if (KeyguardWmStateRefactor.isEnabled) {
86             scope.launch("$TAG#listenForGoneToLockscreenOrHub") {
87                 biometricSettingsRepository.isCurrentUserInLockdown
88                     .distinctUntilChanged()
89                     .filterRelevantKeyguardStateAnd { inLockdown -> inLockdown }
90                     .sample(communalInteractor.isIdleOnCommunal, ::Pair)
91                     .collect { (_, isIdleOnCommunal) ->
92                         val to =
93                             if (isIdleOnCommunal) {
94                                 KeyguardState.GLANCEABLE_HUB
95                             } else {
96                                 KeyguardState.LOCKSCREEN
97                             }
98                         startTransitionTo(to, ownerReason = "User initiated lockdown")
99                     }
100             }
101 
102             scope.launch {
103                 keyguardRepository.isKeyguardEnabled
104                     .filterRelevantKeyguardStateAnd { enabled -> enabled }
105                     .sample(keyguardEnabledInteractor.showKeyguardWhenReenabled)
106                     .filter { reshow -> reshow }
107                     .collect {
108                         startTransitionTo(
109                             KeyguardState.LOCKSCREEN,
110                             ownerReason =
111                                 "Keyguard was re-enabled, and we weren't GONE when it " +
112                                     "was originally disabled"
113                         )
114                     }
115             }
116         } else {
117             scope.launch("$TAG#listenForGoneToLockscreenOrHub") {
118                 keyguardInteractor.isKeyguardShowing
119                     .filterRelevantKeyguardStateAnd { isKeyguardShowing -> isKeyguardShowing }
120                     .sample(communalInteractor.isIdleOnCommunal, ::Pair)
121                     .collect { (_, isIdleOnCommunal) ->
122                         val to =
123                             if (isIdleOnCommunal) {
124                                 KeyguardState.GLANCEABLE_HUB
125                             } else {
126                                 KeyguardState.LOCKSCREEN
127                             }
128                         startTransitionTo(to)
129                     }
130             }
131         }
132     }
133 
134     private fun listenForGoneToDreamingLockscreenHosted() {
135         scope.launch("$TAG#listenForGoneToDreamingLockscreenHosted") {
136             keyguardInteractor.isActiveDreamLockscreenHosted
137                 .filterRelevantKeyguardStateAnd { isActiveDreamLockscreenHosted ->
138                     isActiveDreamLockscreenHosted
139                 }
140                 .collect { startTransitionTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) }
141         }
142     }
143 
144     private fun listenForGoneToDreaming() {
145         scope.launch("$TAG#listenForGoneToDreaming") {
146             keyguardInteractor.isAbleToDream
147                 .sample(keyguardInteractor.isActiveDreamLockscreenHosted, ::Pair)
148                 .filterRelevantKeyguardStateAnd { (isAbleToDream, isActiveDreamLockscreenHosted) ->
149                     isAbleToDream && !isActiveDreamLockscreenHosted
150                 }
151                 .collect { startTransitionTo(KeyguardState.DREAMING) }
152         }
153     }
154 
155     private fun listenForGoneToAodOrDozing() {
156         scope.launch("$TAG#listenForGoneToAodOrDozing") {
157             listenForSleepTransition(
158                 modeOnCanceledFromStartedStep = { TransitionModeOnCanceled.RESET },
159             )
160         }
161     }
162 
163     override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
164         return ValueAnimator().apply {
165             interpolator = Interpolators.LINEAR
166             duration =
167                 when (toState) {
168                     KeyguardState.DREAMING -> TO_DREAMING_DURATION
169                     KeyguardState.AOD -> TO_AOD_DURATION
170                     KeyguardState.DOZING -> TO_DOZING_DURATION
171                     KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION
172                     KeyguardState.GLANCEABLE_HUB -> TO_GLANCEABLE_HUB_DURATION
173                     else -> DEFAULT_DURATION
174                 }.inWholeMilliseconds
175         }
176     }
177 
178     companion object {
179         private const val TAG = "FromGoneTransitionInteractor"
180         private val DEFAULT_DURATION = 500.milliseconds
181         val TO_DREAMING_DURATION = 933.milliseconds
182         val TO_AOD_DURATION = 1300.milliseconds
183         val TO_DOZING_DURATION = 933.milliseconds
184         val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
185         val TO_GLANCEABLE_HUB_DURATION = DEFAULT_DURATION
186     }
187 }
188