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.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC 20 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC 21 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX 22 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED 23 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC 24 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX 25 import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING 26 import android.content.Context 27 import android.content.pm.PackageManager 28 import android.graphics.Bitmap 29 import android.graphics.Canvas 30 import android.graphics.Insets 31 import android.graphics.drawable.BitmapDrawable 32 import android.graphics.drawable.Drawable 33 import android.hardware.biometrics.BiometricManager.Authenticators 34 import android.hardware.biometrics.PromptInfo 35 import android.hardware.biometrics.SensorPropertiesInternal 36 import android.os.UserManager 37 import android.util.DisplayMetrics 38 import android.view.ViewGroup 39 import android.view.WindowInsets 40 import android.view.WindowManager 41 import android.view.WindowMetrics 42 import android.view.accessibility.AccessibilityEvent 43 import android.view.accessibility.AccessibilityManager 44 import com.android.internal.widget.LockPatternUtils 45 import com.android.systemui.biometrics.shared.model.PromptKind 46 47 object Utils { 48 /** Base set of layout flags for fingerprint overlay widgets. */ 49 const val FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS = 50 (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or 51 WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or 52 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or 53 WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) 54 55 @JvmStatic dpToPixelsnull56 fun dpToPixels(context: Context, dp: Float): Float { 57 val density = context.resources.displayMetrics.densityDpi.toFloat() 58 return dp * (density / DisplayMetrics.DENSITY_DEFAULT) 59 } 60 61 /** 62 * Note: Talkback 14.0 has new rate-limitation design to reduce frequency of 63 * TYPE_WINDOW_CONTENT_CHANGED events to once every 30 seconds. (context: b/281765653#comment18) 64 * Using {@link View#announceForAccessibility} instead as workaround when sending events 65 * exceeding this frequency is required. 66 */ 67 @JvmStatic notifyAccessibilityContentChangednull68 fun notifyAccessibilityContentChanged(am: AccessibilityManager, view: ViewGroup) { 69 if (!am.isEnabled) { 70 return 71 } 72 val event = AccessibilityEvent.obtain() 73 event.eventType = AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 74 event.contentChangeTypes = AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE 75 view.sendAccessibilityEventUnchecked(event) 76 view.notifySubtreeAccessibilityStateChanged( 77 view, 78 view, 79 AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE 80 ) 81 } 82 83 @JvmStatic isDeviceCredentialAllowednull84 fun isDeviceCredentialAllowed(promptInfo: PromptInfo): Boolean = 85 (promptInfo.authenticators and Authenticators.DEVICE_CREDENTIAL) != 0 86 87 @JvmStatic 88 fun isBiometricAllowed(promptInfo: PromptInfo): Boolean = 89 (promptInfo.authenticators and Authenticators.BIOMETRIC_WEAK) != 0 90 91 @JvmStatic 92 fun getCredentialType(utils: LockPatternUtils, userId: Int): PromptKind = 93 when (utils.getKeyguardStoredPasswordQuality(userId)) { 94 PASSWORD_QUALITY_SOMETHING -> PromptKind.Pattern 95 PASSWORD_QUALITY_NUMERIC, 96 PASSWORD_QUALITY_NUMERIC_COMPLEX -> PromptKind.Pin 97 PASSWORD_QUALITY_ALPHABETIC, 98 PASSWORD_QUALITY_ALPHANUMERIC, 99 PASSWORD_QUALITY_COMPLEX, 100 PASSWORD_QUALITY_MANAGED -> PromptKind.Password 101 else -> PromptKind.Password 102 } 103 104 @JvmStatic isManagedProfilenull105 fun isManagedProfile(context: Context, userId: Int): Boolean = 106 context.getSystemService(UserManager::class.java)?.isManagedProfile(userId) ?: false 107 108 @JvmStatic 109 fun <T : SensorPropertiesInternal> findFirstSensorProperties( 110 properties: List<T>?, 111 sensorIds: IntArray 112 ): T? = properties?.firstOrNull { sensorIds.contains(it.sensorId) } 113 114 @JvmStatic isSystemnull115 fun isSystem(context: Context, clientPackage: String?): Boolean { 116 val hasPermission = 117 (context.checkCallingOrSelfPermission(Manifest.permission.USE_BIOMETRIC_INTERNAL) == 118 PackageManager.PERMISSION_GRANTED) 119 return hasPermission && "android" == clientPackage 120 } 121 122 @JvmStatic getNavbarInsetsnull123 fun getNavbarInsets(context: Context): Insets { 124 val windowManager: WindowManager? = context.getSystemService(WindowManager::class.java) 125 val windowMetrics: WindowMetrics? = windowManager?.maximumWindowMetrics 126 return windowMetrics?.windowInsets?.getInsets(WindowInsets.Type.navigationBars()) 127 ?: Insets.NONE 128 } 129 130 /** Converts `drawable` to a [Bitmap]. */ 131 @JvmStatic toBitmapnull132 fun Drawable?.toBitmap(): Bitmap? { 133 if (this == null) { 134 return null 135 } 136 if (this is BitmapDrawable) { 137 return bitmap 138 } 139 val bitmap: Bitmap = 140 if (intrinsicWidth <= 0 || intrinsicHeight <= 0) { 141 Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) 142 // Single color bitmap will be created of 1x1 pixel 143 } else { 144 Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888) 145 } 146 val canvas = Canvas(bitmap) 147 setBounds(0, 0, canvas.width, canvas.height) 148 draw(canvas) 149 return bitmap 150 } 151 152 @JvmStatic ellipsizenull153 fun String.ellipsize(cutOffLength: Int) = 154 if (length <= cutOffLength) this else replaceRange(cutOffLength, length, "...") 155 } 156