• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.systemui.animation.Interpolators
21 import com.android.systemui.dagger.SysUISingleton
22 import com.android.systemui.dagger.qualifiers.Application
23 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
24 import com.android.systemui.keyguard.shared.model.KeyguardState
25 import com.android.systemui.keyguard.shared.model.TransitionInfo
26 import com.android.systemui.keyguard.shared.model.WakefulnessState
27 import com.android.systemui.util.kotlin.sample
28 import javax.inject.Inject
29 import kotlin.time.Duration
30 import kotlin.time.Duration.Companion.milliseconds
31 import kotlinx.coroutines.CoroutineScope
32 import kotlinx.coroutines.flow.collect
33 import kotlinx.coroutines.flow.combine
34 import kotlinx.coroutines.launch
35 
36 @SysUISingleton
37 class FromOccludedTransitionInteractor
38 @Inject
39 constructor(
40     @Application private val scope: CoroutineScope,
41     private val keyguardInteractor: KeyguardInteractor,
42     private val keyguardTransitionRepository: KeyguardTransitionRepository,
43     private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
44 ) : TransitionInteractor(FromOccludedTransitionInteractor::class.simpleName!!) {
45 
46     override fun start() {
47         listenForOccludedToLockscreen()
48         listenForOccludedToDreaming()
49         listenForOccludedToAodOrDozing()
50         listenForOccludedToGone()
51     }
52 
53     private fun listenForOccludedToDreaming() {
54         scope.launch {
55             keyguardInteractor.isAbleToDream
56                 .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
57                 .collect { pair ->
58                     val (isAbleToDream, keyguardState) = pair
59                     if (isAbleToDream && keyguardState == KeyguardState.OCCLUDED) {
60                         keyguardTransitionRepository.startTransition(
61                             TransitionInfo(
62                                 name,
63                                 KeyguardState.OCCLUDED,
64                                 KeyguardState.DREAMING,
65                                 getAnimator(),
66                             )
67                         )
68                     }
69                 }
70         }
71     }
72 
73     private fun listenForOccludedToLockscreen() {
74         scope.launch {
75             keyguardInteractor.isKeyguardOccluded
76                 .sample(
77                     combine(
78                         keyguardInteractor.isKeyguardShowing,
79                         keyguardTransitionInteractor.startedKeyguardTransitionStep,
80                         ::Pair
81                     ),
82                     ::toTriple
83                 )
84                 .collect { (isOccluded, isShowing, lastStartedKeyguardState) ->
85                     // Occlusion signals come from the framework, and should interrupt any
86                     // existing transition
87                     if (
88                         !isOccluded &&
89                             isShowing &&
90                             lastStartedKeyguardState.to == KeyguardState.OCCLUDED
91                     ) {
92                         keyguardTransitionRepository.startTransition(
93                             TransitionInfo(
94                                 name,
95                                 KeyguardState.OCCLUDED,
96                                 KeyguardState.LOCKSCREEN,
97                                 getAnimator(TO_LOCKSCREEN_DURATION),
98                             )
99                         )
100                     }
101                 }
102         }
103     }
104 
105     private fun listenForOccludedToGone() {
106         scope.launch {
107             keyguardInteractor.isKeyguardOccluded
108                 .sample(
109                     combine(
110                         keyguardInteractor.isKeyguardShowing,
111                         keyguardTransitionInteractor.startedKeyguardTransitionStep,
112                         ::Pair
113                     ),
114                     ::toTriple
115                 )
116                 .collect { (isOccluded, isShowing, lastStartedKeyguardState) ->
117                     // Occlusion signals come from the framework, and should interrupt any
118                     // existing transition
119                     if (
120                         !isOccluded &&
121                             !isShowing &&
122                             lastStartedKeyguardState.to == KeyguardState.OCCLUDED
123                     ) {
124                         keyguardTransitionRepository.startTransition(
125                             TransitionInfo(
126                                 name,
127                                 KeyguardState.OCCLUDED,
128                                 KeyguardState.GONE,
129                                 getAnimator(),
130                             )
131                         )
132                     }
133                 }
134         }
135     }
136 
137     private fun listenForOccludedToAodOrDozing() {
138         scope.launch {
139             keyguardInteractor.wakefulnessModel
140                 .sample(
141                     combine(
142                         keyguardTransitionInteractor.startedKeyguardTransitionStep,
143                         keyguardInteractor.isAodAvailable,
144                         ::Pair
145                     ),
146                     ::toTriple
147                 )
148                 .collect { (wakefulnessState, lastStartedStep, isAodAvailable) ->
149                     if (
150                         lastStartedStep.to == KeyguardState.OCCLUDED &&
151                             wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
152                     ) {
153                         keyguardTransitionRepository.startTransition(
154                             TransitionInfo(
155                                 name,
156                                 KeyguardState.OCCLUDED,
157                                 if (isAodAvailable) {
158                                     KeyguardState.AOD
159                                 } else {
160                                     KeyguardState.DOZING
161                                 },
162                                 getAnimator(),
163                             )
164                         )
165                     }
166                 }
167         }
168     }
169 
170     private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
171         return ValueAnimator().apply {
172             setInterpolator(Interpolators.LINEAR)
173             setDuration(duration.inWholeMilliseconds)
174         }
175     }
176 
177     companion object {
178         private val DEFAULT_DURATION = 500.milliseconds
179         val TO_LOCKSCREEN_DURATION = 933.milliseconds
180     }
181 }
182