• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.ActivityTaskManager
20 import android.content.Context
21 import android.content.pm.PackageManager
22 import android.graphics.Bitmap
23 import android.graphics.Canvas
24 import android.graphics.Insets
25 import android.graphics.drawable.BitmapDrawable
26 import android.graphics.drawable.Drawable
27 import android.hardware.biometrics.BiometricManager.Authenticators
28 import android.hardware.biometrics.PromptInfo
29 import android.hardware.biometrics.SensorPropertiesInternal
30 import android.os.UserManager
31 import android.util.DisplayMetrics
32 import android.util.Log
33 import android.view.ViewGroup
34 import android.view.WindowInsets
35 import android.view.WindowManager
36 import android.view.WindowMetrics
37 import android.view.accessibility.AccessibilityEvent
38 import android.view.accessibility.AccessibilityManager
39 import com.android.internal.widget.LockPatternUtils
40 import com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
41 import com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN
42 import com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN
43 import com.android.systemui.biometrics.shared.model.PromptKind
44 import com.android.systemui.utils.windowmanager.WindowManagerUtils
45 
46 object Utils {
47     private const val TAG = "SysUIBiometricUtils"
48 
49     /** Base set of layout flags for fingerprint overlay widgets. */
50     const val FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS =
51         (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
52             WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
53             WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
54             WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
55 
56     @JvmStatic
dpToPixelsnull57     fun dpToPixels(context: Context, dp: Float): Float {
58         val density = context.resources.displayMetrics.densityDpi.toFloat()
59         return dp * (density / DisplayMetrics.DENSITY_DEFAULT)
60     }
61 
62     /**
63      * Note: Talkback 14.0 has new rate-limitation design to reduce frequency of
64      * TYPE_WINDOW_CONTENT_CHANGED events to once every 30 seconds. (context: b/281765653#comment18)
65      * Using {@link View#announceForAccessibility} instead as workaround when sending events
66      * exceeding this frequency is required.
67      */
68     @JvmStatic
notifyAccessibilityContentChangednull69     fun notifyAccessibilityContentChanged(am: AccessibilityManager, view: ViewGroup) {
70         if (!am.isEnabled) {
71             return
72         }
73         val event = AccessibilityEvent.obtain()
74         event.eventType = AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
75         event.contentChangeTypes = AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE
76         view.sendAccessibilityEventUnchecked(event)
77         view.notifySubtreeAccessibilityStateChanged(
78             view,
79             view,
80             AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE,
81         )
82     }
83 
84     @JvmStatic
isDeviceCredentialAllowednull85     fun isDeviceCredentialAllowed(promptInfo: PromptInfo): Boolean =
86         (promptInfo.authenticators and Authenticators.DEVICE_CREDENTIAL) != 0
87 
88     @JvmStatic
89     fun isBiometricAllowed(promptInfo: PromptInfo): Boolean =
90         (promptInfo.authenticators and Authenticators.BIOMETRIC_WEAK) != 0
91 
92     @JvmStatic
93     fun getCredentialType(utils: LockPatternUtils, userId: Int): PromptKind =
94         when (utils.getCredentialTypeForUser(userId)) {
95             CREDENTIAL_TYPE_PATTERN -> PromptKind.Pattern
96             CREDENTIAL_TYPE_PIN -> PromptKind.Pin
97             CREDENTIAL_TYPE_PASSWORD -> PromptKind.Password
98             else -> PromptKind.Password
99         }
100 
101     @JvmStatic
isManagedProfilenull102     fun isManagedProfile(context: Context, userId: Int): Boolean =
103         context.getSystemService(UserManager::class.java)?.isManagedProfile(userId) ?: false
104 
105     @JvmStatic
106     fun <T : SensorPropertiesInternal> findFirstSensorProperties(
107         properties: List<T>?,
108         sensorIds: IntArray,
109     ): T? = properties?.firstOrNull { sensorIds.contains(it.sensorId) }
110 
111     @JvmStatic
isSystemnull112     fun isSystem(context: Context, clientPackage: String?): Boolean {
113         val hasPermission =
114             (context.checkCallingOrSelfPermission(Manifest.permission.USE_BIOMETRIC_INTERNAL) ==
115                 PackageManager.PERMISSION_GRANTED)
116         return hasPermission && "android" == clientPackage
117     }
118 
119     @JvmStatic
getNavbarInsetsnull120     fun getNavbarInsets(context: Context): Insets {
121         val windowManager: WindowManager = WindowManagerUtils.getWindowManager(context)
122         val windowMetrics: WindowMetrics = windowManager.maximumWindowMetrics
123         return windowMetrics.windowInsets.getInsets(WindowInsets.Type.navigationBars())
124     }
125 
126     /** Converts `drawable` to a [Bitmap]. */
127     @JvmStatic
toBitmapnull128     fun Drawable?.toBitmap(): Bitmap? {
129         if (this == null) {
130             return null
131         }
132         if (this is BitmapDrawable) {
133             return bitmap
134         }
135         val bitmap: Bitmap =
136             if (intrinsicWidth <= 0 || intrinsicHeight <= 0) {
137                 Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
138                 // Single color bitmap will be created of 1x1 pixel
139             } else {
140                 Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888)
141             }
142         val canvas = Canvas(bitmap)
143         setBounds(0, 0, canvas.width, canvas.height)
144         draw(canvas)
145         return bitmap
146     }
147 
148     @JvmStatic
ellipsizenull149     fun String.ellipsize(cutOffLength: Int) =
150         if (length <= cutOffLength) this else replaceRange(cutOffLength, length, "...")
151 
152     // LINT.IfChange
153     @JvmStatic
154     /**
155      * Checks if a client package is running in the background or it's a system app.
156      *
157      * @param clientPackage The name of the package to be checked.
158      * @param clientClassNameIfItIsConfirmDeviceCredentialActivity The class name of
159      *   ConfirmDeviceCredentialActivity.
160      * @return Whether the client package is running in background
161      */
162     fun ActivityTaskManager.isSystemAppOrInBackground(
163         context: Context,
164         clientPackage: String,
165         clientClassNameIfItIsConfirmDeviceCredentialActivity: String?
166     ): Boolean {
167         Log.v(TAG, "Checking if the authenticating is in background, clientPackage:$clientPackage")
168         val tasks = getTasks(Int.MAX_VALUE)
169         if (tasks == null || tasks.isEmpty()) {
170             Log.w(TAG, "No running tasks reported")
171             return false
172         }
173 
174         val topActivity = tasks[0].topActivity
175         val isSystemApp = isSystem(context, clientPackage)
176         val topPackageEqualsToClient = topActivity!!.packageName == clientPackage
177         val isClientConfirmDeviceCredentialActivity =
178             clientClassNameIfItIsConfirmDeviceCredentialActivity != null
179         // b/339532378: If it's ConfirmDeviceCredentialActivity, we need to check further on
180         // class name.
181         return !(isSystemApp || topPackageEqualsToClient) ||
182             (isClientConfirmDeviceCredentialActivity &&
183                 topActivity.className != clientClassNameIfItIsConfirmDeviceCredentialActivity)
184     }
185     // LINT.ThenChange(frameworks/base/services/core/java/com/android/server/biometrics/Utils.java)
186 }
187