• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2021 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
18 
19 import android.graphics.Bitmap
20 import android.hardware.biometrics.BiometricManager.Authenticators
21 import android.hardware.biometrics.ComponentInfoInternal
22 import android.hardware.biometrics.PromptContentView
23 import android.hardware.biometrics.PromptInfo
24 import android.hardware.biometrics.SensorProperties
25 import android.hardware.biometrics.SensorPropertiesInternal
26 import android.hardware.face.FaceSensorProperties
27 import android.hardware.face.FaceSensorPropertiesInternal
28 import android.hardware.fingerprint.FingerprintSensorProperties
29 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
30 import com.android.keyguard.keyguardUpdateMonitor
31 import com.android.systemui.SysuiTestableContext
32 import com.android.systemui.biometrics.data.repository.biometricStatusRepository
33 import com.android.systemui.biometrics.shared.model.AuthenticationReason
34 import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
35 import com.android.systemui.kosmos.Kosmos
36 import com.android.systemui.res.R
37 import com.android.systemui.util.mockito.whenever
38 import kotlinx.coroutines.test.TestScope
39 import kotlinx.coroutines.test.runCurrent
40 
41 /** Create [FingerprintSensorPropertiesInternal] for a test. */
42 internal fun fingerprintSensorPropertiesInternal(
43     ids: List<Int> = listOf(0),
44     strong: Boolean = true,
45     sensorType: Int = FingerprintSensorProperties.TYPE_REAR,
46 ): List<FingerprintSensorPropertiesInternal> {
47     val componentInfo =
48         listOf(
49             ComponentInfoInternal(
50                 "fingerprintSensor" /* componentId */,
51                 "vendor/model/revision" /* hardwareVersion */,
52                 "1.01" /* firmwareVersion */,
53                 "00000001" /* serialNumber */,
54                 "", /* softwareVersion */
55             ),
56             ComponentInfoInternal(
57                 "matchingAlgorithm" /* componentId */,
58                 "" /* hardwareVersion */,
59                 "" /* firmwareVersion */,
60                 "" /* serialNumber */,
61                 "vendor/version/revision", /* softwareVersion */
62             ),
63         )
64     return ids.map { id ->
65         FingerprintSensorPropertiesInternal(
66             id,
67             if (strong) SensorProperties.STRENGTH_STRONG else SensorProperties.STRENGTH_WEAK,
68             5 /* maxEnrollmentsPerUser */,
69             componentInfo,
70             sensorType,
71             false, /* resetLockoutRequiresHardwareAuthToken */
72         )
73     }
74 }
75 
76 /** Create [FaceSensorPropertiesInternal] for a test. */
faceSensorPropertiesInternalnull77 internal fun faceSensorPropertiesInternal(
78     ids: List<Int> = listOf(1),
79     strong: Boolean = true,
80 ): List<FaceSensorPropertiesInternal> {
81     val componentInfo =
82         listOf(
83             ComponentInfoInternal(
84                 "faceSensor" /* componentId */,
85                 "vendor/model/revision" /* hardwareVersion */,
86                 "1.01" /* firmwareVersion */,
87                 "00000001" /* serialNumber */,
88                 "", /* softwareVersion */
89             ),
90             ComponentInfoInternal(
91                 "matchingAlgorithm" /* componentId */,
92                 "" /* hardwareVersion */,
93                 "" /* firmwareVersion */,
94                 "" /* serialNumber */,
95                 "vendor/version/revision", /* softwareVersion */
96             ),
97         )
98     return ids.map { id ->
99         FaceSensorPropertiesInternal(
100             id,
101             if (strong) SensorProperties.STRENGTH_STRONG else SensorProperties.STRENGTH_WEAK,
102             2 /* maxEnrollmentsPerUser */,
103             componentInfo,
104             FaceSensorProperties.TYPE_RGB,
105             true /* supportsFaceDetection */,
106             true /* supportsSelfIllumination */,
107             false, /* resetLockoutRequiresHardwareAuthToken */
108         )
109     }
110 }
111 
112 @Authenticators.Types
extractAuthenticatorTypesnull113 internal fun Collection<SensorPropertiesInternal?>.extractAuthenticatorTypes(): Int {
114     var authenticators = Authenticators.EMPTY_SET
115     mapNotNull { it?.sensorStrength }
116         .forEach { strength ->
117             authenticators =
118                 authenticators or
119                     when (strength) {
120                         SensorProperties.STRENGTH_CONVENIENCE ->
121                             Authenticators.BIOMETRIC_CONVENIENCE
122                         SensorProperties.STRENGTH_WEAK -> Authenticators.BIOMETRIC_WEAK
123                         SensorProperties.STRENGTH_STRONG -> Authenticators.BIOMETRIC_STRONG
124                         else -> Authenticators.EMPTY_SET
125                     }
126         }
127     return authenticators
128 }
129 
promptInfonull130 internal fun promptInfo(
131     logoRes: Int = -1,
132     logoBitmap: Bitmap? = null,
133     logoDescription: String? = null,
134     title: String = "title",
135     subtitle: String = "sub",
136     description: String = "desc",
137     contentView: PromptContentView? = null,
138     credentialTitle: String? = "cred title",
139     credentialSubtitle: String? = "cred sub",
140     credentialDescription: String? = "cred desc",
141     negativeButton: String = "neg",
142 ): PromptInfo {
143     val info = PromptInfo()
144     if (logoBitmap != null) {
145         info.setLogo(logoRes, logoBitmap)
146     }
147     info.logoDescription = logoDescription
148     info.title = title
149     info.subtitle = subtitle
150     info.description = description
151     info.contentView = contentView
152     credentialTitle?.let { info.deviceCredentialTitle = it }
153     credentialSubtitle?.let { info.deviceCredentialSubtitle = it }
154     credentialDescription?.let { info.deviceCredentialDescription = it }
155     info.negativeButtonText = negativeButton
156     return info
157 }
158 
updateSfpsIndicatorRequestsnull159 internal fun TestScope.updateSfpsIndicatorRequests(
160     kosmos: Kosmos,
161     mContext: SysuiTestableContext,
162     primaryBouncerRequest: Boolean? = null,
163     alternateBouncerRequest: Boolean? = null,
164     biometricPromptRequest: Boolean? = null,
165     // TODO(b/365182034): update when rest to unlock feature is implemented
166     //    progressBarShowing: Boolean? = null
167 ) {
168     biometricPromptRequest?.let { hasBiometricPromptRequest ->
169         if (hasBiometricPromptRequest) {
170             kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
171                 AuthenticationReason.BiometricPromptAuthentication
172             )
173         } else {
174             kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
175                 AuthenticationReason.NotRunning
176             )
177         }
178     }
179 
180     primaryBouncerRequest?.let { hasPrimaryBouncerRequest ->
181         updatePrimaryBouncer(
182             kosmos,
183             mContext,
184             isShowing = hasPrimaryBouncerRequest,
185             isAnimatingAway = false,
186             fpsDetectionRunning = true,
187             isUnlockingWithFpAllowed = true,
188         )
189     }
190 
191     alternateBouncerRequest?.let { hasAlternateBouncerRequest ->
192         kosmos.keyguardBouncerRepository.setAlternateVisible(hasAlternateBouncerRequest)
193     }
194 
195     // TODO(b/365182034): set progress bar visibility when rest to unlock feature is implemented
196 
197     runCurrent()
198 }
199 
updatePrimaryBouncernull200 internal fun updatePrimaryBouncer(
201     kosmos: Kosmos,
202     mContext: SysuiTestableContext,
203     isShowing: Boolean,
204     isAnimatingAway: Boolean,
205     fpsDetectionRunning: Boolean,
206     isUnlockingWithFpAllowed: Boolean,
207 ) {
208     kosmos.keyguardBouncerRepository.setPrimaryShow(isShowing)
209     kosmos.keyguardBouncerRepository.setPrimaryStartingToHide(false)
210     val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
211     kosmos.keyguardBouncerRepository.setPrimaryStartDisappearAnimation(
212         primaryStartDisappearAnimation
213     )
214 
215     whenever(kosmos.keyguardUpdateMonitor.isFingerprintDetectionRunning)
216         .thenReturn(fpsDetectionRunning)
217     whenever(kosmos.keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
218         .thenReturn(isUnlockingWithFpAllowed)
219     mContext.orCreateTestableResources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer, true)
220 }
221