• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.animation.ValueAnimator
20 import com.android.app.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.BiometricUnlockModel
25 import com.android.systemui.keyguard.shared.model.DozeStateModel
26 import com.android.systemui.keyguard.shared.model.KeyguardState
27 import com.android.systemui.util.kotlin.Utils.Companion.toTriple
28 import com.android.systemui.util.kotlin.sample
29 import javax.inject.Inject
30 import kotlin.time.Duration.Companion.milliseconds
31 import kotlinx.coroutines.CoroutineScope
32 import kotlinx.coroutines.delay
33 import kotlinx.coroutines.flow.combine
34 import kotlinx.coroutines.flow.onEach
35 import kotlinx.coroutines.launch
36 
37 @SysUISingleton
38 class FromDreamingLockscreenHostedTransitionInteractor
39 @Inject
40 constructor(
41     override val transitionRepository: KeyguardTransitionRepository,
42     override val transitionInteractor: KeyguardTransitionInteractor,
43     @Application private val scope: CoroutineScope,
44     private val keyguardInteractor: KeyguardInteractor,
45 ) :
46     TransitionInteractor(
47         fromState = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
48     ) {
49 
50     override fun start() {
51         listenForDreamingLockscreenHostedToLockscreen()
52         listenForDreamingLockscreenHostedToGone()
53         listenForDreamingLockscreenHostedToDozing()
54         listenForDreamingLockscreenHostedToOccluded()
55         listenForDreamingLockscreenHostedToPrimaryBouncer()
56     }
57 
58     private fun listenForDreamingLockscreenHostedToLockscreen() {
59         scope.launch {
60             keyguardInteractor.isActiveDreamLockscreenHosted
61                 // Add a slight delay to prevent transitioning to lockscreen from happening too soon
62                 // as dozing can arrive in a slight gap after the lockscreen hosted dream stops.
63                 .onEach { delay(50) }
64                 .sample(
65                     combine(
66                         keyguardInteractor.dozeTransitionModel,
67                         transitionInteractor.startedKeyguardTransitionStep,
68                         ::Pair
69                     ),
70                     ::toTriple
71                 )
72                 .collect {
73                     (isActiveDreamLockscreenHosted, dozeTransitionModel, lastStartedTransition) ->
74                     if (
75                         !isActiveDreamLockscreenHosted &&
76                             DozeStateModel.isDozeOff(dozeTransitionModel.to) &&
77                             lastStartedTransition.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
78                     ) {
79                         startTransitionTo(KeyguardState.LOCKSCREEN)
80                     }
81                 }
82         }
83     }
84 
85     private fun listenForDreamingLockscreenHostedToOccluded() {
86         scope.launch {
87             keyguardInteractor.isActiveDreamLockscreenHosted
88                 .sample(
89                     combine(
90                         keyguardInteractor.isKeyguardOccluded,
91                         transitionInteractor.startedKeyguardTransitionStep,
92                         ::Pair,
93                     ),
94                     ::toTriple
95                 )
96                 .collect { (isActiveDreamLockscreenHosted, isOccluded, lastStartedTransition) ->
97                     if (
98                         isOccluded &&
99                             !isActiveDreamLockscreenHosted &&
100                             lastStartedTransition.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
101                     ) {
102                         startTransitionTo(KeyguardState.OCCLUDED)
103                     }
104                 }
105         }
106     }
107 
108     private fun listenForDreamingLockscreenHostedToPrimaryBouncer() {
109         scope.launch {
110             keyguardInteractor.primaryBouncerShowing
111                 .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
112                 .collect { (isBouncerShowing, lastStartedTransitionStep) ->
113                     if (
114                         isBouncerShowing &&
115                             lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
116                     ) {
117                         startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
118                     }
119                 }
120         }
121     }
122 
123     private fun listenForDreamingLockscreenHostedToGone() {
124         scope.launch {
125             keyguardInteractor.biometricUnlockState
126                 .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
127                 .collect { (biometricUnlockState, lastStartedTransitionStep) ->
128                     if (
129                         lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED &&
130                             biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM
131                     ) {
132                         startTransitionTo(KeyguardState.GONE)
133                     }
134                 }
135         }
136     }
137 
138     private fun listenForDreamingLockscreenHostedToDozing() {
139         scope.launch {
140             combine(
141                     keyguardInteractor.dozeTransitionModel,
142                     transitionInteractor.startedKeyguardTransitionStep,
143                     ::Pair
144                 )
145                 .collect { (dozeTransitionModel, lastStartedTransitionStep) ->
146                     if (
147                         dozeTransitionModel.to == DozeStateModel.DOZE &&
148                             lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
149                     ) {
150                         startTransitionTo(KeyguardState.DOZING)
151                     }
152                 }
153         }
154     }
155 
156     override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
157         return ValueAnimator().apply {
158             interpolator = Interpolators.LINEAR
159             duration =
160                 if (toState == KeyguardState.LOCKSCREEN) TO_LOCKSCREEN_DURATION.inWholeMilliseconds
161                 else DEFAULT_DURATION.inWholeMilliseconds
162         }
163     }
164 
165     companion object {
166         private val DEFAULT_DURATION = 500.milliseconds
167         val TO_LOCKSCREEN_DURATION = 1167.milliseconds
168     }
169 }
170