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