1 /* 2 * Copyright (C) 2022 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.FingerprintSensorProperties; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.util.AttributeSet; 26 import android.util.RotationUtils; 27 import android.view.Gravity; 28 import android.view.Surface; 29 import android.view.ViewGroup; 30 import android.widget.FrameLayout; 31 import android.widget.ImageView; 32 33 import androidx.annotation.NonNull; 34 import androidx.annotation.Nullable; 35 36 import com.android.settings.R; 37 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams; 38 39 /** 40 * View corresponding with udfps_enroll_view.xml 41 */ 42 public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Listener { 43 private static final String TAG = "UdfpsEnrollView"; 44 @NonNull 45 private final UdfpsEnrollDrawable mFingerprintDrawable; 46 @NonNull 47 private final UdfpsEnrollProgressBarDrawable mFingerprintProgressDrawable; 48 @NonNull 49 private final Handler mHandler; 50 51 @NonNull 52 private ImageView mFingerprintProgressView; 53 54 private int mProgressBarRadius; 55 56 // sensorRect may be bigger than the sensor. True sensor dimensions are defined in 57 // overlayParams.sensorBounds 58 private Rect mSensorRect; 59 private UdfpsOverlayParams mOverlayParams; 60 UdfpsEnrollView(Context context, @Nullable AttributeSet attrs)61 public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) { 62 super(context, attrs); 63 mFingerprintDrawable = new UdfpsEnrollDrawable(mContext, attrs); 64 mFingerprintProgressDrawable = new UdfpsEnrollProgressBarDrawable(context, attrs); 65 mHandler = new Handler(Looper.getMainLooper()); 66 } 67 68 @Override onFinishInflate()69 protected void onFinishInflate() { 70 ImageView fingerprintView = findViewById(R.id.udfps_enroll_animation_fp_view); 71 fingerprintView.setImageDrawable(mFingerprintDrawable); 72 mFingerprintProgressView = findViewById(R.id.udfps_enroll_animation_fp_progress_view); 73 mFingerprintProgressView.setImageDrawable(mFingerprintProgressDrawable); 74 } 75 76 // Implements UdfpsEnrollHelper.Listener 77 @Override onEnrollmentProgress(int remaining, int totalSteps)78 public void onEnrollmentProgress(int remaining, int totalSteps) { 79 mHandler.post(() -> { 80 mFingerprintProgressDrawable.onEnrollmentProgress(remaining, totalSteps); 81 mFingerprintDrawable.onEnrollmentProgress(remaining, totalSteps); 82 }); 83 } 84 85 @Override onEnrollmentHelp(int remaining, int totalSteps)86 public void onEnrollmentHelp(int remaining, int totalSteps) { 87 mHandler.post(() -> mFingerprintProgressDrawable.onEnrollmentHelp(remaining, totalSteps)); 88 } 89 90 @Override onAcquired(boolean animateIfLastStepGood)91 public void onAcquired(boolean animateIfLastStepGood) { 92 mHandler.post(() -> { 93 onFingerUp(); 94 if (animateIfLastStepGood) mFingerprintProgressDrawable.onLastStepAcquired(); 95 }); 96 } 97 98 @Override onPointerDown(int sensorId)99 public void onPointerDown(int sensorId) { 100 onFingerDown(); 101 } 102 103 @Override onPointerUp(int sensorId)104 public void onPointerUp(int sensorId) { 105 onFingerUp(); 106 } 107 getOverlayParams()108 public UdfpsOverlayParams getOverlayParams() { 109 return mOverlayParams; 110 } 111 112 /** 113 * Set UdfpsOverlayParams 114 */ setOverlayParams(UdfpsOverlayParams params)115 public void setOverlayParams(UdfpsOverlayParams params) { 116 mOverlayParams = params; 117 118 post(() -> { 119 mProgressBarRadius = 120 (int) (mOverlayParams.getScaleFactor() * getContext().getResources().getInteger( 121 R.integer.config_udfpsEnrollProgressBar)); 122 mSensorRect = new Rect(mOverlayParams.getSensorBounds()); 123 124 onSensorRectUpdated(); 125 }); 126 } 127 128 /** 129 * Set UdfpsEnrollHelper 130 */ setEnrollHelper(UdfpsEnrollHelper enrollHelper)131 public void setEnrollHelper(UdfpsEnrollHelper enrollHelper) { 132 mFingerprintDrawable.setEnrollHelper(enrollHelper); 133 enrollHelper.setListener(this); 134 } 135 onSensorRectUpdated()136 private void onSensorRectUpdated() { 137 updateDimensions(); 138 139 // Updates sensor rect in relation to the overlay view 140 mSensorRect.set(getPaddingX(), getPaddingY(), 141 (mOverlayParams.getSensorBounds().width() + getPaddingX()), 142 (mOverlayParams.getSensorBounds().height() + getPaddingY())); 143 mFingerprintDrawable.onSensorRectUpdated(new RectF(mSensorRect)); 144 } 145 updateDimensions()146 private void updateDimensions() { 147 // Original sensorBounds assume portrait mode. 148 final Rect rotatedBounds = new Rect(mOverlayParams.getSensorBounds()); 149 int rotation = mOverlayParams.getRotation(); 150 if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) { 151 RotationUtils.rotateBounds( 152 rotatedBounds, 153 mOverlayParams.getNaturalDisplayWidth(), 154 mOverlayParams.getNaturalDisplayHeight(), 155 rotation 156 ); 157 } 158 159 // Use parent view's and rotatedBound's absolute coordinates to decide the margins of 160 // UdfpsEnrollView, so that its center keeps consistent with sensor rect's. 161 ViewGroup parentView = (ViewGroup) getParent(); 162 MarginLayoutParams marginLayoutParams = (MarginLayoutParams) getLayoutParams(); 163 FrameLayout.LayoutParams params = (LayoutParams) getLayoutParams(); 164 if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { 165 final int[] coords = parentView.getLocationOnScreen(); 166 final int parentLeft = coords[0]; 167 final int parentTop = coords[1]; 168 final int parentRight = parentLeft + parentView.getWidth(); 169 params.gravity = Gravity.RIGHT | Gravity.TOP; 170 final int rightMargin = parentRight - rotatedBounds.right - getPaddingX(); 171 final int topMargin = rotatedBounds.top - parentTop - getPaddingY(); 172 if (marginLayoutParams.rightMargin == rightMargin 173 && marginLayoutParams.topMargin == topMargin) { 174 return; 175 } 176 marginLayoutParams.rightMargin = rightMargin; 177 marginLayoutParams.topMargin = topMargin; 178 setLayoutParams(params); 179 } else { 180 final int[] coords = parentView.getLocationOnScreen(); 181 final int parentLeft = coords[0]; 182 final int parentTop = coords[1]; 183 final int parentRight = parentLeft + parentView.getWidth(); 184 final int parentBottom = parentTop + parentView.getHeight(); 185 if (rotation == Surface.ROTATION_90) { 186 params.gravity = Gravity.RIGHT | Gravity.BOTTOM; 187 marginLayoutParams.rightMargin = parentRight - rotatedBounds.right - getPaddingX(); 188 marginLayoutParams.bottomMargin = 189 parentBottom - rotatedBounds.bottom - getPaddingY(); 190 } else if (rotation == Surface.ROTATION_270) { 191 params.gravity = Gravity.LEFT | Gravity.BOTTOM; 192 marginLayoutParams.leftMargin = rotatedBounds.left - parentLeft - getPaddingX(); 193 marginLayoutParams.bottomMargin = 194 parentBottom - rotatedBounds.bottom - getPaddingY(); 195 } 196 } 197 198 params.height = rotatedBounds.height() + 2 * getPaddingX(); 199 params.width = rotatedBounds.width() + 2 * getPaddingY(); 200 setLayoutParams(params); 201 202 203 } 204 onFingerDown()205 private void onFingerDown() { 206 if (mOverlayParams.getSensorType() == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { 207 mFingerprintDrawable.setShouldSkipDraw(true); 208 } 209 mFingerprintDrawable.invalidateSelf(); 210 } 211 onFingerUp()212 private void onFingerUp() { 213 mFingerprintDrawable.setShouldSkipDraw(false); 214 mFingerprintDrawable.invalidateSelf(); 215 } 216 getPaddingX()217 private int getPaddingX() { 218 return mProgressBarRadius; 219 } 220 getPaddingY()221 private int getPaddingY() { 222 return mProgressBarRadius; 223 } 224 } 225