1 /* 2 * 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.settings.biometrics.fingerprint; 18 19 import android.content.Context; 20 import android.graphics.Rect; 21 import android.graphics.RectF; 22 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 23 import android.util.AttributeSet; 24 import android.util.Log; 25 import android.util.RotationUtils; 26 import android.view.DisplayInfo; 27 import android.view.MotionEvent; 28 import android.view.Surface; 29 import android.widget.ImageView; 30 import android.widget.RelativeLayout; 31 32 import androidx.annotation.NonNull; 33 import androidx.annotation.Nullable; 34 35 import com.android.settings.R; 36 import com.android.systemui.biometrics.UdfpsUtils; 37 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams; 38 39 /** 40 * View corresponding with fingerprint_check_enrolled_dialog.xml 41 */ 42 public class UdfpsCheckEnrolledView extends RelativeLayout { 43 private static final String TAG = "UdfpsCheckEnrolledView"; 44 @NonNull 45 private final UdfpsFingerprintDrawable mFingerprintDrawable; 46 private ImageView mFingerprintView; 47 private UdfpsUtils mUdfpsUtils; 48 49 private @Nullable Rect mSensorRect; 50 private @Nullable UdfpsOverlayParams mOverlayParams; 51 private @Nullable FingerprintSensorPropertiesInternal mSensorProperties; 52 53 UdfpsCheckEnrolledView(@onNull Context context, @Nullable AttributeSet attrs)54 public UdfpsCheckEnrolledView(@NonNull Context context, @Nullable AttributeSet attrs) { 55 super(context, attrs); 56 mFingerprintDrawable = new UdfpsFingerprintDrawable(mContext, attrs); 57 mUdfpsUtils = new UdfpsUtils(); 58 } 59 60 @Override onFinishInflate()61 protected void onFinishInflate() { 62 super.onFinishInflate(); 63 mFingerprintView = findViewById(R.id.udfps_fingerprint_sensor_view); 64 mFingerprintView.setImageDrawable(mFingerprintDrawable); 65 mFingerprintView.setOnTouchListener((v, event) -> { 66 if (event.getAction() == MotionEvent.ACTION_DOWN) { 67 Log.d(TAG, "Fingerprint view touched!"); 68 return true; 69 } 70 return false; 71 }); 72 } 73 74 /** 75 * setup SensorProperties 76 */ setSensorProperties(@ullable FingerprintSensorPropertiesInternal properties)77 public void setSensorProperties(@Nullable FingerprintSensorPropertiesInternal properties) { 78 mSensorProperties = properties; 79 updateOverlayParams(); 80 } 81 onSensorRectUpdated()82 private void onSensorRectUpdated() { 83 updateDimensions(); 84 85 if (mSensorRect == null || mOverlayParams == null) { 86 Log.e(TAG, "Fail to onSensorRectUpdated, mSensorRect/mOverlayParams null"); 87 return; 88 } 89 90 // Updates sensor rect in relation to the overlay view 91 mSensorRect.set(0, 0, 92 mOverlayParams.getSensorBounds().width(), 93 mOverlayParams.getSensorBounds().height()); 94 mFingerprintDrawable.onSensorRectUpdated(new RectF(mSensorRect)); 95 } 96 updateDimensions()97 private void updateDimensions() { 98 if (mOverlayParams == null) { 99 Log.e(TAG, "Fail to updateDimensions for " + this + ", mOverlayParams null"); 100 return; 101 } 102 // Original sensorBounds assume portrait mode. 103 final Rect rotatedBounds = new Rect(mOverlayParams.getSensorBounds()); 104 int rotation = mOverlayParams.getRotation(); 105 if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) { 106 RotationUtils.rotateBounds( 107 rotatedBounds, 108 mOverlayParams.getNaturalDisplayWidth(), 109 mOverlayParams.getNaturalDisplayHeight(), 110 rotation 111 ); 112 } 113 114 RelativeLayout parent = ((RelativeLayout) getParent()); 115 if (parent == null) { 116 Log.e(TAG, "Fail to updateDimensions for " + this + ", parent null"); 117 return; 118 } 119 final int[] coords = parent.getLocationOnScreen(); 120 final int parentLeft = coords[0]; 121 final int parentTop = coords[1]; 122 final int parentRight = parentLeft + parent.getWidth(); 123 124 // Update container view LayoutParams 125 RelativeLayout.LayoutParams checkEnrolledViewLp = 126 new RelativeLayout.LayoutParams(getWidth(), getHeight()); 127 checkEnrolledViewLp.addRule(RelativeLayout.ALIGN_PARENT_TOP); 128 if (rotation == Surface.ROTATION_90) { 129 checkEnrolledViewLp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); 130 checkEnrolledViewLp.width = 131 rotatedBounds.width() + 2 * (parentRight - rotatedBounds.right); 132 } else { 133 checkEnrolledViewLp.addRule(RelativeLayout.ALIGN_PARENT_LEFT); 134 checkEnrolledViewLp.width = rotatedBounds.width() + 2 * rotatedBounds.left; 135 } 136 setLayoutParams(checkEnrolledViewLp); 137 138 // Update fingerprint view LayoutParams 139 RelativeLayout.LayoutParams fingerprintViewLp = new RelativeLayout.LayoutParams( 140 rotatedBounds.width(), rotatedBounds.height()); 141 fingerprintViewLp.addRule(RelativeLayout.ALIGN_PARENT_TOP); 142 fingerprintViewLp.topMargin = rotatedBounds.top - parentTop; 143 if (rotation == Surface.ROTATION_90) { 144 fingerprintViewLp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); 145 fingerprintViewLp.rightMargin = parentRight - rotatedBounds.right; 146 } else { 147 fingerprintViewLp.addRule(RelativeLayout.ALIGN_PARENT_LEFT); 148 fingerprintViewLp.leftMargin = rotatedBounds.left - parentLeft; 149 } 150 mFingerprintView.setLayoutParams(fingerprintViewLp); 151 } 152 updateOverlayParams()153 private void updateOverlayParams() { 154 155 if (mSensorProperties == null) { 156 android.util.Log.e(TAG, "There is no sensor info!"); 157 return; 158 } 159 160 DisplayInfo displayInfo = new DisplayInfo(); 161 if (getDisplay() == null) { 162 android.util.Log.e(TAG, "Can not get display"); 163 return; 164 } 165 getDisplay().getDisplayInfo(displayInfo); 166 Rect udfpsBounds = mSensorProperties.getLocation().getRect(); 167 float scaleFactor = mUdfpsUtils.getScaleFactor(displayInfo); 168 udfpsBounds.scale(scaleFactor); 169 170 final Rect overlayBounds = new Rect( 171 0, /* left */ 172 displayInfo.getNaturalHeight() / 2, /* top */ 173 displayInfo.getNaturalWidth(), /* right */ 174 displayInfo.getNaturalHeight() /* botom */); 175 176 mOverlayParams = new UdfpsOverlayParams( 177 udfpsBounds, 178 overlayBounds, 179 displayInfo.getNaturalWidth(), 180 displayInfo.getNaturalHeight(), 181 scaleFactor, 182 displayInfo.rotation, 183 mSensorProperties.sensorType); 184 185 post(() -> { 186 if (mOverlayParams == null) { 187 Log.e(TAG, "Fail to updateOverlayParams, mOverlayParams null"); 188 return; 189 } 190 mSensorRect = new Rect(mOverlayParams.getSensorBounds()); 191 onSensorRectUpdated(); 192 }); 193 } 194 } 195