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.app.animation.Interpolators 21 import com.android.app.tracing.coroutines.launch 22 import com.android.systemui.communal.domain.interactor.CommunalInteractor 23 import com.android.systemui.dagger.SysUISingleton 24 import com.android.systemui.dagger.qualifiers.Background 25 import com.android.systemui.dagger.qualifiers.Main 26 import com.android.systemui.keyguard.KeyguardWmStateRefactor 27 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository 28 import com.android.systemui.keyguard.data.repository.KeyguardRepository 29 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository 30 import com.android.systemui.keyguard.shared.model.KeyguardState 31 import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled 32 import com.android.systemui.power.domain.interactor.PowerInteractor 33 import com.android.systemui.scene.shared.flag.SceneContainerFlag 34 import com.android.systemui.util.kotlin.sample 35 import javax.inject.Inject 36 import kotlin.time.Duration.Companion.milliseconds 37 import kotlinx.coroutines.CoroutineDispatcher 38 import kotlinx.coroutines.CoroutineScope 39 import kotlinx.coroutines.flow.distinctUntilChanged 40 import kotlinx.coroutines.flow.filter 41 import kotlinx.coroutines.launch 42 43 @SysUISingleton 44 class FromGoneTransitionInteractor 45 @Inject 46 constructor( 47 override val transitionRepository: KeyguardTransitionRepository, 48 transitionInteractor: KeyguardTransitionInteractor, 49 @Background private val scope: CoroutineScope, 50 @Background bgDispatcher: CoroutineDispatcher, 51 @Main mainDispatcher: CoroutineDispatcher, 52 keyguardInteractor: KeyguardInteractor, 53 powerInteractor: PowerInteractor, 54 private val communalInteractor: CommunalInteractor, 55 keyguardOcclusionInteractor: KeyguardOcclusionInteractor, 56 private val biometricSettingsRepository: BiometricSettingsRepository, 57 private val keyguardRepository: KeyguardRepository, 58 private val keyguardEnabledInteractor: KeyguardEnabledInteractor, 59 ) : 60 TransitionInteractor( 61 fromState = KeyguardState.GONE, 62 transitionInteractor = transitionInteractor, 63 mainDispatcher = mainDispatcher, 64 bgDispatcher = bgDispatcher, 65 powerInteractor = powerInteractor, 66 keyguardOcclusionInteractor = keyguardOcclusionInteractor, 67 keyguardInteractor = keyguardInteractor, 68 ) { 69 70 override fun start() { 71 // TODO(b/336576536): Check if adaptation for scene framework is needed 72 if (SceneContainerFlag.isEnabled) return 73 listenForGoneToAodOrDozing() 74 listenForGoneToDreaming() 75 listenForGoneToLockscreenOrHub() 76 listenForGoneToDreamingLockscreenHosted() 77 } 78 79 fun showKeyguard() { 80 scope.launch("$TAG#showKeyguard") { startTransitionTo(KeyguardState.LOCKSCREEN) } 81 } 82 83 // Primarily for when the user chooses to lock down the device 84 private fun listenForGoneToLockscreenOrHub() { 85 if (KeyguardWmStateRefactor.isEnabled) { 86 scope.launch("$TAG#listenForGoneToLockscreenOrHub") { 87 biometricSettingsRepository.isCurrentUserInLockdown 88 .distinctUntilChanged() 89 .filterRelevantKeyguardStateAnd { inLockdown -> inLockdown } 90 .sample(communalInteractor.isIdleOnCommunal, ::Pair) 91 .collect { (_, isIdleOnCommunal) -> 92 val to = 93 if (isIdleOnCommunal) { 94 KeyguardState.GLANCEABLE_HUB 95 } else { 96 KeyguardState.LOCKSCREEN 97 } 98 startTransitionTo(to, ownerReason = "User initiated lockdown") 99 } 100 } 101 102 scope.launch { 103 keyguardRepository.isKeyguardEnabled 104 .filterRelevantKeyguardStateAnd { enabled -> enabled } 105 .sample(keyguardEnabledInteractor.showKeyguardWhenReenabled) 106 .filter { reshow -> reshow } 107 .collect { 108 startTransitionTo( 109 KeyguardState.LOCKSCREEN, 110 ownerReason = 111 "Keyguard was re-enabled, and we weren't GONE when it " + 112 "was originally disabled" 113 ) 114 } 115 } 116 } else { 117 scope.launch("$TAG#listenForGoneToLockscreenOrHub") { 118 keyguardInteractor.isKeyguardShowing 119 .filterRelevantKeyguardStateAnd { isKeyguardShowing -> isKeyguardShowing } 120 .sample(communalInteractor.isIdleOnCommunal, ::Pair) 121 .collect { (_, isIdleOnCommunal) -> 122 val to = 123 if (isIdleOnCommunal) { 124 KeyguardState.GLANCEABLE_HUB 125 } else { 126 KeyguardState.LOCKSCREEN 127 } 128 startTransitionTo(to) 129 } 130 } 131 } 132 } 133 134 private fun listenForGoneToDreamingLockscreenHosted() { 135 scope.launch("$TAG#listenForGoneToDreamingLockscreenHosted") { 136 keyguardInteractor.isActiveDreamLockscreenHosted 137 .filterRelevantKeyguardStateAnd { isActiveDreamLockscreenHosted -> 138 isActiveDreamLockscreenHosted 139 } 140 .collect { startTransitionTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) } 141 } 142 } 143 144 private fun listenForGoneToDreaming() { 145 scope.launch("$TAG#listenForGoneToDreaming") { 146 keyguardInteractor.isAbleToDream 147 .sample(keyguardInteractor.isActiveDreamLockscreenHosted, ::Pair) 148 .filterRelevantKeyguardStateAnd { (isAbleToDream, isActiveDreamLockscreenHosted) -> 149 isAbleToDream && !isActiveDreamLockscreenHosted 150 } 151 .collect { startTransitionTo(KeyguardState.DREAMING) } 152 } 153 } 154 155 private fun listenForGoneToAodOrDozing() { 156 scope.launch("$TAG#listenForGoneToAodOrDozing") { 157 listenForSleepTransition( 158 modeOnCanceledFromStartedStep = { TransitionModeOnCanceled.RESET }, 159 ) 160 } 161 } 162 163 override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator { 164 return ValueAnimator().apply { 165 interpolator = Interpolators.LINEAR 166 duration = 167 when (toState) { 168 KeyguardState.DREAMING -> TO_DREAMING_DURATION 169 KeyguardState.AOD -> TO_AOD_DURATION 170 KeyguardState.DOZING -> TO_DOZING_DURATION 171 KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION 172 KeyguardState.GLANCEABLE_HUB -> TO_GLANCEABLE_HUB_DURATION 173 else -> DEFAULT_DURATION 174 }.inWholeMilliseconds 175 } 176 } 177 178 companion object { 179 private const val TAG = "FromGoneTransitionInteractor" 180 private val DEFAULT_DURATION = 500.milliseconds 181 val TO_DREAMING_DURATION = 933.milliseconds 182 val TO_AOD_DURATION = 1300.milliseconds 183 val TO_DOZING_DURATION = 933.milliseconds 184 val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION 185 val TO_GLANCEABLE_HUB_DURATION = DEFAULT_DURATION 186 } 187 } 188