1 /* 2 * 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 18 package com.android.systemui.keyguard.domain.interactor 19 20 import android.util.Log 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.KeyguardState.ALTERNATE_BOUNCER 26 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD 27 import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING 28 import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING 29 import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING_LOCKSCREEN_HOSTED 30 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE 31 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN 32 import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED 33 import com.android.systemui.keyguard.shared.model.KeyguardState.OFF 34 import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER 35 import com.android.systemui.keyguard.shared.model.TransitionState 36 import com.android.systemui.keyguard.shared.model.TransitionStep 37 import javax.inject.Inject 38 import kotlinx.coroutines.CoroutineScope 39 import kotlinx.coroutines.flow.Flow 40 import kotlinx.coroutines.flow.SharingStarted 41 import kotlinx.coroutines.flow.StateFlow 42 import kotlinx.coroutines.flow.combine 43 import kotlinx.coroutines.flow.filter 44 import kotlinx.coroutines.flow.map 45 import kotlinx.coroutines.flow.merge 46 import kotlinx.coroutines.flow.stateIn 47 48 /** Encapsulates business-logic related to the keyguard transitions. */ 49 @SysUISingleton 50 class KeyguardTransitionInteractor 51 @Inject 52 constructor( 53 @Application val scope: CoroutineScope, 54 private val repository: KeyguardTransitionRepository, 55 private val keyguardInteractor: dagger.Lazy<KeyguardInteractor>, 56 private val fromLockscreenTransitionInteractor: dagger.Lazy<FromLockscreenTransitionInteractor>, 57 private val fromPrimaryBouncerTransitionInteractor: 58 dagger.Lazy<FromPrimaryBouncerTransitionInteractor>, 59 ) { 60 private val TAG = this::class.simpleName 61 62 /** (any)->GONE transition information */ 63 val anyStateToGoneTransition: Flow<TransitionStep> = 64 repository.transitions.filter { step -> step.to == GONE } 65 66 /** (any)->AOD transition information */ 67 val anyStateToAodTransition: Flow<TransitionStep> = 68 repository.transitions.filter { step -> step.to == AOD } 69 70 /** DREAMING->(any) transition information. */ 71 val fromDreamingTransition: Flow<TransitionStep> = 72 repository.transitions.filter { step -> step.from == DREAMING } 73 74 /** (any)->Lockscreen transition information */ 75 val anyStateToLockscreenTransition: Flow<TransitionStep> = 76 repository.transitions.filter { step -> step.to == LOCKSCREEN } 77 78 /** (any)->Occluded transition information */ 79 val anyStateToOccludedTransition: Flow<TransitionStep> = 80 repository.transitions.filter { step -> step.to == OCCLUDED } 81 82 /** (any)->PrimaryBouncer transition information */ 83 val anyStateToPrimaryBouncerTransition: Flow<TransitionStep> = 84 repository.transitions.filter { step -> step.to == PRIMARY_BOUNCER } 85 86 /** (any)->Dreaming transition information */ 87 val anyStateToDreamingTransition: Flow<TransitionStep> = 88 repository.transitions.filter { step -> step.to == DREAMING } 89 90 /** (any)->AlternateBouncer transition information */ 91 val anyStateToAlternateBouncerTransition: Flow<TransitionStep> = 92 repository.transitions.filter { step -> step.to == ALTERNATE_BOUNCER } 93 94 /** AOD->LOCKSCREEN transition information. */ 95 val aodToLockscreenTransition: Flow<TransitionStep> = repository.transition(AOD, LOCKSCREEN) 96 97 /** DREAMING->LOCKSCREEN transition information. */ 98 val dreamingToLockscreenTransition: Flow<TransitionStep> = 99 repository.transition(DREAMING, LOCKSCREEN) 100 101 /** DREAMING_LOCKSCREEN_HOSTED->LOCKSCREEN transition information. */ 102 val dreamingLockscreenHostedToLockscreenTransition: Flow<TransitionStep> = 103 repository.transition(DREAMING_LOCKSCREEN_HOSTED, LOCKSCREEN) 104 105 /** GONE->AOD transition information. */ 106 val goneToAodTransition: Flow<TransitionStep> = repository.transition(GONE, AOD) 107 108 /** GONE->DREAMING transition information. */ 109 val goneToDreamingTransition: Flow<TransitionStep> = repository.transition(GONE, DREAMING) 110 111 /** GONE->DREAMING_LOCKSCREEN_HOSTED transition information. */ 112 val goneToDreamingLockscreenHostedTransition: Flow<TransitionStep> = 113 repository.transition(GONE, DREAMING_LOCKSCREEN_HOSTED) 114 115 /** LOCKSCREEN->AOD transition information. */ 116 val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD) 117 118 /** LOCKSCREEN->DREAMING transition information. */ 119 val lockscreenToDreamingTransition: Flow<TransitionStep> = 120 repository.transition(LOCKSCREEN, DREAMING) 121 122 /** LOCKSCREEN->DREAMING_LOCKSCREEN_HOSTED transition information. */ 123 val lockscreenToDreamingLockscreenHostedTransition: Flow<TransitionStep> = 124 repository.transition(LOCKSCREEN, DREAMING_LOCKSCREEN_HOSTED) 125 126 /** LOCKSCREEN->OCCLUDED transition information. */ 127 val lockscreenToOccludedTransition: Flow<TransitionStep> = 128 repository.transition(LOCKSCREEN, OCCLUDED) 129 130 /** OCCLUDED->LOCKSCREEN transition information. */ 131 val occludedToLockscreenTransition: Flow<TransitionStep> = 132 repository.transition(OCCLUDED, LOCKSCREEN) 133 134 /** PRIMARY_BOUNCER->GONE transition information. */ 135 val primaryBouncerToGoneTransition: Flow<TransitionStep> = 136 repository.transition(PRIMARY_BOUNCER, GONE) 137 138 /** OFF->LOCKSCREEN transition information. */ 139 val offToLockscreenTransition: Flow<TransitionStep> = repository.transition(OFF, LOCKSCREEN) 140 141 /** DOZING->LOCKSCREEN transition information. */ 142 val dozingToLockscreenTransition: Flow<TransitionStep> = 143 repository.transition(DOZING, LOCKSCREEN) 144 145 /** 146 * AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <-> 147 * Lockscreen (0f). 148 */ 149 val dozeAmountTransition: Flow<TransitionStep> = 150 merge( 151 aodToLockscreenTransition.map { step -> step.copy(value = 1f - step.value) }, 152 lockscreenToAodTransition, 153 ) 154 155 /** The last [TransitionStep] with a [TransitionState] of STARTED */ 156 val startedKeyguardTransitionStep: Flow<TransitionStep> = 157 repository.transitions.filter { step -> step.transitionState == TransitionState.STARTED } 158 159 /** The last [TransitionStep] with a [TransitionState] of CANCELED */ 160 val canceledKeyguardTransitionStep: Flow<TransitionStep> = 161 repository.transitions.filter { step -> step.transitionState == TransitionState.CANCELED } 162 163 /** The last [TransitionStep] with a [TransitionState] of FINISHED */ 164 val finishedKeyguardTransitionStep: Flow<TransitionStep> = 165 repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED } 166 167 /** The destination state of the last started transition. */ 168 val startedKeyguardState: StateFlow<KeyguardState> = 169 startedKeyguardTransitionStep 170 .map { step -> step.to } 171 .stateIn(scope, SharingStarted.Eagerly, OFF) 172 173 /** The last completed [KeyguardState] transition */ 174 val finishedKeyguardState: StateFlow<KeyguardState> = 175 finishedKeyguardTransitionStep 176 .map { step -> step.to } 177 .stateIn(scope, SharingStarted.Eagerly, LOCKSCREEN) 178 179 /** 180 * Whether we're currently in a transition to a new [KeyguardState] and haven't yet completed 181 * it. 182 */ 183 val isInTransitionToAnyState = 184 combine( 185 startedKeyguardTransitionStep, 186 finishedKeyguardState, 187 ) { startedStep, finishedState -> 188 startedStep.to != finishedState 189 } 190 191 /** 192 * The amount of transition into or out of the given [KeyguardState]. 193 * 194 * The value will be `0` (or close to `0`, due to float point arithmetic) if not in this step or 195 * `1` when fully in the given state. 196 */ 197 fun transitionValue( 198 state: KeyguardState, 199 ): Flow<Float> { 200 return repository.transitions 201 .filter { it.from == state || it.to == state } 202 .map { 203 if (it.from == state) { 204 1 - it.value 205 } else { 206 it.value 207 } 208 } 209 } 210 211 fun transitionStepsFromState(fromState: KeyguardState): Flow<TransitionStep> { 212 return repository.transitions.filter { step -> step.from == fromState } 213 } 214 215 fun transitionStepsToState(toState: KeyguardState): Flow<TransitionStep> { 216 return repository.transitions.filter { step -> step.to == toState } 217 } 218 219 /** 220 * Called to start a transition that will ultimately dismiss the keyguard from the current 221 * state. 222 */ 223 fun startDismissKeyguardTransition() { 224 when (startedKeyguardState.value) { 225 LOCKSCREEN -> fromLockscreenTransitionInteractor.get().dismissKeyguard() 226 PRIMARY_BOUNCER -> fromPrimaryBouncerTransitionInteractor.get().dismissPrimaryBouncer() 227 else -> 228 Log.e( 229 "KeyguardTransitionInteractor", 230 "We don't know how to dismiss keyguard from state " + 231 "${startedKeyguardState.value}" 232 ) 233 } 234 } 235 236 /** Whether we're in a transition to the given [KeyguardState], but haven't yet completed it. */ 237 fun isInTransitionToState( 238 state: KeyguardState, 239 ): Flow<Boolean> { 240 return combine( 241 startedKeyguardTransitionStep, 242 finishedKeyguardState, 243 ) { startedStep, finishedState -> 244 startedStep.to == state && finishedState != state 245 } 246 } 247 } 248