1 /* 2 * 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 18 package com.android.systemui.keyguard.domain.interactor 19 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.dagger.qualifiers.Application 22 import com.android.systemui.keyguard.data.repository.KeyguardRepository 23 import com.android.systemui.keyguard.shared.model.DismissAction 24 import com.android.systemui.keyguard.shared.model.KeyguardDone 25 import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER 26 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE 27 import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER 28 import com.android.systemui.scene.domain.interactor.SceneInteractor 29 import com.android.systemui.scene.shared.flag.SceneContainerFlag 30 import com.android.systemui.scene.shared.model.Scenes 31 import com.android.systemui.util.kotlin.sample 32 import javax.inject.Inject 33 import kotlinx.coroutines.CoroutineScope 34 import kotlinx.coroutines.ExperimentalCoroutinesApi 35 import kotlinx.coroutines.flow.Flow 36 import kotlinx.coroutines.flow.SharingStarted 37 import kotlinx.coroutines.flow.StateFlow 38 import kotlinx.coroutines.flow.filter 39 import kotlinx.coroutines.flow.filterNot 40 import kotlinx.coroutines.flow.map 41 import kotlinx.coroutines.flow.merge 42 import kotlinx.coroutines.flow.stateIn 43 44 /** Encapsulates business-logic for actions to run when the keyguard is dismissed. */ 45 @ExperimentalCoroutinesApi 46 @SysUISingleton 47 class KeyguardDismissActionInteractor 48 @Inject 49 constructor( 50 private val repository: KeyguardRepository, 51 transitionInteractor: KeyguardTransitionInteractor, 52 val dismissInteractor: KeyguardDismissInteractor, 53 @Application private val applicationScope: CoroutineScope, 54 sceneInteractor: SceneInteractor, 55 ) { 56 val dismissAction: Flow<DismissAction> = repository.dismissAction 57 <lambda>null58 val onCancel: Flow<Runnable> = dismissAction.map { it.onCancelAction } 59 60 // TODO (b/268240415): use message in alt + primary bouncer message 61 // message to show to the user about the dismiss action, else empty string <lambda>null62 val message = dismissAction.map { it.message } 63 64 /** 65 * True if the dismiss action will run an animation on the lockscreen and requires any views 66 * that would obscure this animation (ie: the primary bouncer) to immediately hide, so the 67 * animation would be visible. 68 */ 69 val willAnimateDismissActionOnLockscreen: StateFlow<Boolean> = 70 dismissAction <lambda>null71 .map { it.willAnimateOnLockscreen } 72 .stateIn( 73 scope = applicationScope, 74 started = SharingStarted.WhileSubscribed(), 75 initialValue = false, 76 ) 77 78 private val finishedTransitionToGone: Flow<Unit> = 79 if (SceneContainerFlag.isEnabled) { <lambda>null80 sceneInteractor.transitionState.filter { it.isIdle(Scenes.Gone) }.map {} 81 } else { <lambda>null82 transitionInteractor.finishedKeyguardState.filter { it == GONE }.map {} 83 } 84 85 val executeDismissAction: Flow<() -> KeyguardDone> = 86 merge( 87 finishedTransitionToGone, 88 dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction 89 ) 90 .sample(dismissAction) <lambda>null91 .filterNot { it is DismissAction.None } <lambda>null92 .map { it.onDismissAction } 93 val resetDismissAction: Flow<Unit> = 94 transitionInteractor.finishedKeyguardTransitionStep <lambda>null95 .filter { it.to != ALTERNATE_BOUNCER && it.to != PRIMARY_BOUNCER && it.to != GONE } 96 .sample(dismissAction) <lambda>null97 .filterNot { it is DismissAction.None } <lambda>null98 .map {} // map to Unit 99 runDismissAnimationOnKeyguardnull100 fun runDismissAnimationOnKeyguard(): Boolean { 101 return willAnimateDismissActionOnLockscreen.value 102 } 103 runAfterKeyguardGonenull104 fun runAfterKeyguardGone(runnable: Runnable) { 105 setDismissAction( 106 DismissAction.RunAfterKeyguardGone( 107 dismissAction = { runnable.run() }, 108 onCancelAction = {}, 109 message = "", 110 willAnimateOnLockscreen = false, 111 ) 112 ) 113 } 114 setDismissActionnull115 fun setDismissAction(dismissAction: DismissAction) { 116 repository.dismissAction.value.onCancelAction.run() 117 repository.setDismissAction(dismissAction) 118 } 119 handleDismissActionnull120 fun handleDismissAction() { 121 repository.setDismissAction(DismissAction.None) 122 } 123 setKeyguardDonenull124 suspend fun setKeyguardDone(keyguardDoneTiming: KeyguardDone) { 125 dismissInteractor.setKeyguardDone(keyguardDoneTiming) 126 } 127 } 128