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.biometrics.domain.interactor 18 19 import android.content.Context 20 import android.graphics.Rect 21 import android.hardware.biometrics.SensorLocationInternal 22 import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository 23 import com.android.systemui.biometrics.shared.model.SensorLocation 24 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor 25 import com.android.systemui.dagger.SysUISingleton 26 import com.android.systemui.dagger.qualifiers.Application 27 import javax.inject.Inject 28 import kotlinx.coroutines.CoroutineScope 29 import kotlinx.coroutines.flow.Flow 30 import kotlinx.coroutines.flow.SharingStarted 31 import kotlinx.coroutines.flow.StateFlow 32 import kotlinx.coroutines.flow.combine 33 import kotlinx.coroutines.flow.distinctUntilChanged 34 import kotlinx.coroutines.flow.filterNotNull 35 import kotlinx.coroutines.flow.map 36 import kotlinx.coroutines.flow.stateIn 37 38 @SysUISingleton 39 class FingerprintPropertyInteractor 40 @Inject 41 constructor( 42 @Application private val applicationScope: CoroutineScope, 43 @Application private val context: Context, 44 repository: FingerprintPropertyRepository, 45 configurationInteractor: ConfigurationInteractor, 46 displayStateInteractor: DisplayStateInteractor, 47 udfpsOverlayInteractor: UdfpsOverlayInteractor, 48 ) { 49 val propertiesInitialized: Flow<Boolean> = repository.propertiesInitialized 50 val isUdfps: StateFlow<Boolean> = 51 repository.sensorType 52 .map { it.isUdfps() } 53 .stateIn( 54 scope = applicationScope, 55 started = SharingStarted.Eagerly, 56 initialValue = repository.sensorType.value.isUdfps(), 57 ) 58 59 /** 60 * Devices with multiple physical displays use unique display ids to determine which sensor is 61 * on the active physical display. This value represents a unique physical display id. 62 */ 63 private val uniqueDisplayId: Flow<String> = 64 displayStateInteractor.displayChanges 65 .map { context.display?.uniqueId } 66 .filterNotNull() 67 .distinctUntilChanged() 68 69 /** 70 * Sensor location for the: 71 * - current physical display 72 * - device's natural screen resolution 73 * - device's natural orientation 74 */ 75 private val unscaledSensorLocation: Flow<SensorLocationInternal> = 76 combine( 77 repository.sensorLocations, 78 uniqueDisplayId, 79 ) { locations, displayId -> 80 // Devices without multiple physical displays do not use the display id as the key; 81 // instead, the key is an empty string. 82 locations.getOrDefault( 83 displayId, 84 locations.getOrDefault("", SensorLocationInternal.DEFAULT) 85 ) 86 } 87 88 /** 89 * Sensor location for the: 90 * - current physical display 91 * - current screen resolution 92 * - device's natural orientation 93 */ 94 val sensorLocation: Flow<SensorLocation> = 95 combine( 96 unscaledSensorLocation, 97 configurationInteractor.scaleForResolution, 98 ) { unscaledSensorLocation, scale -> 99 val sensorLocation = 100 SensorLocation( 101 naturalCenterX = unscaledSensorLocation.sensorLocationX, 102 naturalCenterY = unscaledSensorLocation.sensorLocationY, 103 naturalRadius = unscaledSensorLocation.sensorRadius, 104 scale = scale 105 ) 106 sensorLocation 107 } 108 109 /** 110 * Sensor location for the: 111 * - current physical display 112 * - current screen resolution 113 * - device's current orientation 114 */ 115 val udfpsSensorBounds: Flow<Rect> = 116 udfpsOverlayInteractor.udfpsOverlayParams.map { it.sensorBounds }.distinctUntilChanged() 117 } 118