1 /*
2  * Copyright (C) 2019 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 package com.android.systemui.biometrics
17 
18 import android.Manifest
19 import android.annotation.IntDef
20 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
21 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
22 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
23 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED
24 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
25 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
26 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
27 import android.content.Context
28 import android.content.pm.PackageManager
29 import android.graphics.Insets
30 import android.hardware.biometrics.BiometricManager.Authenticators
31 import android.hardware.biometrics.PromptInfo
32 import android.hardware.biometrics.SensorPropertiesInternal
33 import android.os.UserManager
34 import android.util.DisplayMetrics
35 import android.view.ViewGroup
36 import android.view.WindowInsets
37 import android.view.WindowManager
38 import android.view.WindowMetrics
39 import android.view.accessibility.AccessibilityEvent
40 import android.view.accessibility.AccessibilityManager
41 import com.android.internal.widget.LockPatternUtils
42 import java.lang.annotation.Retention
43 import java.lang.annotation.RetentionPolicy
44 
45 object Utils {
46     const val CREDENTIAL_PIN = 1
47     const val CREDENTIAL_PATTERN = 2
48     const val CREDENTIAL_PASSWORD = 3
49 
50     /** Base set of layout flags for fingerprint overlay widgets.  */
51     const val FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS =
52         (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
53             or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
54             or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
55             or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
56 
57     @JvmStatic
58     fun dpToPixels(context: Context, dp: Float): Float {
59         val density = context.resources.displayMetrics.densityDpi.toFloat()
60         return dp * (density / DisplayMetrics.DENSITY_DEFAULT)
61     }
62 
63     /**
64      * Note: Talkback 14.0 has new rate-limitation design to reduce frequency
65      * of TYPE_WINDOW_CONTENT_CHANGED events to once every 30 seconds.
66      * (context: b/281765653#comment18)
67      * Using {@link View#announceForAccessibility} instead as workaround when sending events
68      * exceeding this frequency is required.
69      */
70     @JvmStatic
71     fun notifyAccessibilityContentChanged(am: AccessibilityManager, view: ViewGroup) {
72         if (!am.isEnabled) {
73             return
74         }
75         val event = AccessibilityEvent.obtain()
76         event.eventType = AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
77         event.contentChangeTypes =
78             AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE
79         view.sendAccessibilityEventUnchecked(event)
80         view.notifySubtreeAccessibilityStateChanged(
81             view,
82             view,
83             AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE
84         )
85     }
86 
87     @JvmStatic
88     fun isDeviceCredentialAllowed(promptInfo: PromptInfo): Boolean =
89         (promptInfo.authenticators and Authenticators.DEVICE_CREDENTIAL) != 0
90 
91     @JvmStatic
92     fun isBiometricAllowed(promptInfo: PromptInfo): Boolean =
93         (promptInfo.authenticators and Authenticators.BIOMETRIC_WEAK) != 0
94 
95     @JvmStatic
96     @CredentialType
97     fun getCredentialType(utils: LockPatternUtils, userId: Int): Int =
98         when (utils.getKeyguardStoredPasswordQuality(userId)) {
99             PASSWORD_QUALITY_SOMETHING -> CREDENTIAL_PATTERN
100             PASSWORD_QUALITY_NUMERIC,
101             PASSWORD_QUALITY_NUMERIC_COMPLEX -> CREDENTIAL_PIN
102             PASSWORD_QUALITY_ALPHABETIC,
103             PASSWORD_QUALITY_ALPHANUMERIC,
104             PASSWORD_QUALITY_COMPLEX,
105             PASSWORD_QUALITY_MANAGED -> CREDENTIAL_PASSWORD
106             else -> CREDENTIAL_PASSWORD
107         }
108 
109     @JvmStatic
110     fun isManagedProfile(context: Context, userId: Int): Boolean =
111         context.getSystemService(UserManager::class.java)?.isManagedProfile(userId) ?: false
112 
113     @JvmStatic
114     fun <T : SensorPropertiesInternal> findFirstSensorProperties(
115         properties: List<T>?,
116         sensorIds: IntArray
117     ): T? = properties?.firstOrNull { sensorIds.contains(it.sensorId) }
118 
119     @JvmStatic
120     fun isSystem(context: Context, clientPackage: String?): Boolean {
121         val hasPermission =
122             (context.checkCallingOrSelfPermission(Manifest.permission.USE_BIOMETRIC_INTERNAL)
123                 == PackageManager.PERMISSION_GRANTED)
124         return hasPermission && "android" == clientPackage
125     }
126 
127     @JvmStatic
128     fun getNavbarInsets(context: Context): Insets {
129         val windowManager: WindowManager? = context.getSystemService(WindowManager::class.java)
130         val windowMetrics: WindowMetrics? = windowManager?.maximumWindowMetrics
131         return windowMetrics?.windowInsets?.getInsets(WindowInsets.Type.navigationBars())
132             ?: Insets.NONE
133     }
134 
135     @Retention(RetentionPolicy.SOURCE)
136     @IntDef(CREDENTIAL_PIN, CREDENTIAL_PATTERN, CREDENTIAL_PASSWORD)
137     internal annotation class CredentialType
138 }