• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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