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