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.biometrics.domain.interactor 18 19 import android.hardware.biometrics.AuthenticateOptions 20 import android.hardware.biometrics.IBiometricContextListener 21 import android.util.Log 22 import com.android.systemui.dagger.SysUISingleton 23 import com.android.systemui.dagger.qualifiers.Application 24 import com.android.systemui.display.data.repository.DeviceStateRepository 25 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor 26 import com.android.systemui.keyguard.shared.model.KeyguardState 27 import javax.inject.Inject 28 import kotlinx.coroutines.CoroutineScope 29 import kotlinx.coroutines.Job 30 import kotlinx.coroutines.cancel 31 import kotlinx.coroutines.flow.Flow 32 import kotlinx.coroutines.flow.SharingStarted 33 import kotlinx.coroutines.flow.catch 34 import kotlinx.coroutines.flow.distinctUntilChanged 35 import kotlinx.coroutines.flow.launchIn 36 import kotlinx.coroutines.flow.map 37 import kotlinx.coroutines.flow.onEach 38 import kotlinx.coroutines.flow.shareIn 39 import kotlinx.coroutines.launch 40 41 /** 42 * Aggregates UI/device state that is not directly related to biometrics, but is often useful for 43 * logging or optimization purposes (fold state, screen state, etc.) 44 */ 45 interface LogContextInteractor { 46 47 /** If the device is showing aod. */ 48 val isAod: Flow<Boolean> 49 50 /** If the device is currently awake with the screen on. */ 51 val isAwake: Flow<Boolean> 52 53 /** Current device fold state, defined as [IBiometricContextListener.FoldState]. */ 54 val foldState: Flow<Int> 55 56 /** Current display state, defined as [AuthenticateOptions.DisplayState] */ 57 val displayState: Flow<Int> 58 59 /** If touches on the fingerprint sensor should be ignored by the HAL. */ 60 val isHardwareIgnoringTouches: Flow<Boolean> 61 62 /** 63 * Add a permanent context listener. 64 * 65 * Use this method for registering remote context listeners. Use the properties exposed via this 66 * class directly within SysUI. 67 */ 68 fun addBiometricContextListener(listener: IBiometricContextListener): Job 69 } 70 71 @SysUISingleton 72 class LogContextInteractorImpl 73 @Inject 74 constructor( 75 @Application private val applicationScope: CoroutineScope, 76 deviceStateRepository: DeviceStateRepository, 77 keyguardTransitionInteractor: KeyguardTransitionInteractor, 78 udfpsOverlayInteractor: UdfpsOverlayInteractor, 79 ) : LogContextInteractor { 80 81 override val displayState = <lambda>null82 keyguardTransitionInteractor.startedKeyguardTransitionStep.map { 83 when (it.to) { 84 KeyguardState.LOCKSCREEN, 85 KeyguardState.OCCLUDED, 86 KeyguardState.ALTERNATE_BOUNCER, 87 KeyguardState.PRIMARY_BOUNCER -> AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN 88 KeyguardState.AOD -> AuthenticateOptions.DISPLAY_STATE_AOD 89 KeyguardState.OFF, 90 KeyguardState.DOZING -> AuthenticateOptions.DISPLAY_STATE_NO_UI 91 KeyguardState.DREAMING -> AuthenticateOptions.DISPLAY_STATE_SCREENSAVER 92 else -> AuthenticateOptions.DISPLAY_STATE_UNKNOWN 93 } 94 } 95 96 override val isHardwareIgnoringTouches: Flow<Boolean> = shouldHandlenull97 udfpsOverlayInteractor.shouldHandleTouches.map { shouldHandle -> !shouldHandle } 98 99 override val isAod = <lambda>null100 displayState.map { it == AuthenticateOptions.DISPLAY_STATE_AOD }.distinctUntilChanged() 101 102 override val isAwake = 103 displayState <lambda>null104 .map { 105 when (it) { 106 AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN, 107 AuthenticateOptions.DISPLAY_STATE_SCREENSAVER, 108 AuthenticateOptions.DISPLAY_STATE_UNKNOWN -> true 109 else -> false 110 } 111 } 112 .distinctUntilChanged() 113 114 override val foldState: Flow<Int> = 115 deviceStateRepository.state <lambda>null116 .map { 117 when (it) { 118 DeviceStateRepository.DeviceState.UNFOLDED, 119 DeviceStateRepository.DeviceState.REAR_DISPLAY, 120 DeviceStateRepository.DeviceState.CONCURRENT_DISPLAY -> 121 IBiometricContextListener.FoldState.FULLY_OPENED 122 DeviceStateRepository.DeviceState.FOLDED -> 123 IBiometricContextListener.FoldState.FULLY_CLOSED 124 DeviceStateRepository.DeviceState.HALF_FOLDED -> 125 IBiometricContextListener.FoldState.HALF_OPENED 126 else -> IBiometricContextListener.FoldState.UNKNOWN 127 } 128 } 129 .distinctUntilChanged() 130 .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1) 131 addBiometricContextListenernull132 override fun addBiometricContextListener(listener: IBiometricContextListener): Job { 133 return applicationScope.launch { 134 foldState 135 .onEach { state -> listener.onFoldChanged(state) } 136 .catch { t -> Log.w(TAG, "failed to notify new fold state", t) } 137 .launchIn(this) 138 139 displayState 140 .distinctUntilChanged() 141 .onEach { state -> listener.onDisplayStateChanged(state) } 142 .catch { t -> Log.w(TAG, "failed to notify new display state", t) } 143 .launchIn(this) 144 145 isHardwareIgnoringTouches 146 .distinctUntilChanged() 147 .onEach { state -> listener.onHardwareIgnoreTouchesChanged(state) } 148 .catch { t -> Log.w(TAG, "failed to notify new set ignore state", t) } 149 .launchIn(this) 150 151 listener.asBinder().linkToDeath({ cancel() }, 0) 152 } 153 } 154 155 companion object { 156 private const val TAG = "ContextRepositoryImpl" 157 } 158 } 159