1 /* <lambda>null2 * Copyright (C) 2024 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.annotation.SuppressLint 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.dagger.qualifiers.Background 22 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository 23 import com.android.systemui.util.kotlin.sample 24 import javax.inject.Inject 25 import kotlinx.coroutines.CoroutineScope 26 import kotlinx.coroutines.flow.Flow 27 import kotlinx.coroutines.flow.MutableSharedFlow 28 import kotlinx.coroutines.flow.distinctUntilChanged 29 import kotlinx.coroutines.flow.filter 30 import kotlinx.coroutines.flow.map 31 import kotlinx.coroutines.flow.merge 32 import kotlinx.coroutines.launch 33 34 /** The reason we're showing lockscreen while awake, used for logging. */ 35 enum class ShowWhileAwakeReason(private val logReason: String) { 36 FOLDED_WITH_SWIPE_UP_TO_CONTINUE( 37 "Folded with continue using apps on fold set to 'swipe up to continue'." 38 ), 39 LOCKDOWN("Lockdown initiated."), 40 KEYGUARD_REENABLED( 41 "Keyguard was re-enabled. We weren't unlocked when it was disabled, " + 42 "so we're returning to the lockscreen." 43 ), 44 KEYGUARD_TIMEOUT_WHILE_SCREEN_ON( 45 "Timed out while the screen was kept on, or WM#lockNow() was called." 46 ), 47 SWITCHED_TO_SECURE_USER_WHILE_GOING_AWAY( 48 "User switch to secure user occurred during keyguardGoingAway sequence, so we're locking." 49 ); 50 51 override fun toString(): String { 52 return logReason 53 } 54 } 55 56 /** 57 * Logic around cases where the we show the lockscreen while still awake (transition from GONE -> 58 * LOCKSCREEN), vs. the more common cases of a power button press or screen timeout, which result in 59 * the device going to sleep. 60 * 61 * This does not necessarily mean we lock the device (which does not happen if showing the 62 * lockscreen is triggered by [KeyguardService.showDismissibleKeyguard]). We'll show keyguard here 63 * and authentication logic will decide if that keyguard is dismissible or not. 64 * 65 * This is possible in the following situations: 66 * - The user initiates lockdown from the power menu. 67 * - Theft detection, etc. has requested lockdown. 68 * - The keyguard was disabled while visible, and has now been re-enabled, so it's re-showing. 69 * - Someone called WM#lockNow(). 70 * - The screen timed out, but an activity with FLAG_ALLOW_LOCK_WHILE_SCREEN_ON is on top. 71 * - A foldable is folded with "Continue using apps on fold" set to "Swipe up to continue" (if set 72 * to "never", then lockscreen will be shown when the device goes to sleep, which is not tnohe 73 * concern of this interactor). 74 */ 75 @SysUISingleton 76 class KeyguardShowWhileAwakeInteractor 77 @Inject 78 constructor( 79 @Background val backgroundScope: CoroutineScope, 80 biometricSettingsRepository: BiometricSettingsRepository, 81 keyguardEnabledInteractor: KeyguardEnabledInteractor, 82 keyguardServiceShowLockscreenInteractor: KeyguardServiceShowLockscreenInteractor, 83 ) { 84 85 /** Emits whenever the current user is in lockdown mode. */ 86 private val inLockdown: Flow<ShowWhileAwakeReason> = 87 biometricSettingsRepository.isCurrentUserInLockdown 88 .distinctUntilChanged() inLockdownnull89 .filter { inLockdown -> inLockdown } <lambda>null90 .map { ShowWhileAwakeReason.LOCKDOWN } 91 92 /** 93 * Emits whenever the keyguard is re-enabled, and we need to return to lockscreen due to the 94 * device being locked when the keyguard was originally disabled. 95 */ 96 private val keyguardReenabled: Flow<ShowWhileAwakeReason> = 97 keyguardEnabledInteractor.isKeyguardEnabled enablednull98 .filter { enabled -> enabled } 99 .sample(keyguardEnabledInteractor.showKeyguardWhenReenabled) reshownull100 .filter { reshow -> reshow } <lambda>null101 .map { ShowWhileAwakeReason.KEYGUARD_REENABLED } 102 103 /** 104 * Emits whenever a user switch to a secure user occurs during keyguard going away. 105 * 106 * This is an event flow, hence the SharedFlow. 107 */ 108 @SuppressLint("SharedFlowCreation") 109 val switchedToSecureUserDuringGoingAway: MutableSharedFlow<ShowWhileAwakeReason> = 110 MutableSharedFlow() 111 112 /** Emits whenever we should show lockscreen while the screen is on, for any reason. */ 113 val showWhileAwakeEvents: Flow<ShowWhileAwakeReason> = 114 merge( 115 // We're in lockdown, and the keyguard is enabled. If the keyguard is disabled, the 116 // lockdown button is hidden in the UI, but it's still possible to trigger lockdown in 117 // tests. 118 inLockdown <lambda>null119 .filter { keyguardEnabledInteractor.isKeyguardEnabledAndNotSuppressed() } <lambda>null120 .map { ShowWhileAwakeReason.LOCKDOWN }, 121 // The keyguard was re-enabled, and it was showing when it was originally disabled. 122 // Tests currently expect that if the keyguard is re-enabled, it will show even if it's 123 // suppressed, so we don't check for isKeyguardEnabledAndNotSuppressed() on this flow. <lambda>null124 keyguardReenabled.map { ShowWhileAwakeReason.KEYGUARD_REENABLED }, 125 // KeyguardService says we need to show now, and the lockscreen is enabled. <lambda>null126 keyguardServiceShowLockscreenInteractor.showNowEvents.filter { 127 keyguardEnabledInteractor.isKeyguardEnabledAndNotSuppressed() 128 }, 129 switchedToSecureUserDuringGoingAway, 130 ) 131 132 /** A user switch to a secure user occurred while we were going away. We need to re-lock. */ onSwitchedToSecureUserWhileKeyguardGoingAwaynull133 fun onSwitchedToSecureUserWhileKeyguardGoingAway() { 134 backgroundScope.launch { 135 switchedToSecureUserDuringGoingAway.emit( 136 ShowWhileAwakeReason.SWITCHED_TO_SECURE_USER_WHILE_GOING_AWAY 137 ) 138 } 139 } 140 } 141