• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.systemui.biometrics;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.graphics.PointF;
23 import android.hardware.fingerprint.IUdfpsOverlayController;
24 import android.os.Build;
25 import android.os.UserHandle;
26 import android.provider.Settings;
27 import android.util.Log;
28 import android.util.TypedValue;
29 import android.view.accessibility.AccessibilityManager;
30 
31 import java.util.ArrayList;
32 import java.util.List;
33 
34 /**
35  * Helps keep track of enrollment state and animates the progress bar accordingly.
36  */
37 public class UdfpsEnrollHelper {
38     private static final String TAG = "UdfpsEnrollHelper";
39 
40     private static final String SCALE_OVERRIDE =
41             "com.android.systemui.biometrics.UdfpsEnrollHelper.scale";
42     private static final float SCALE = 0.5f;
43 
44     private static final String NEW_COORDS_OVERRIDE =
45             "com.android.systemui.biometrics.UdfpsNewCoords";
46 
47     // Enroll with two center touches before going to guided enrollment
48     private static final int NUM_CENTER_TOUCHES = 2;
49 
50     interface Listener {
onEnrollmentProgress(int remaining, int totalSteps)51         void onEnrollmentProgress(int remaining, int totalSteps);
onLastStepAcquired()52         void onLastStepAcquired();
53     }
54 
55     @NonNull private final Context mContext;
56     // IUdfpsOverlayController reason
57     private final int mEnrollReason;
58     private final boolean mAccessibilityEnabled;
59     @NonNull private final List<PointF> mGuidedEnrollmentPoints;
60 
61     private int mTotalSteps = -1;
62     private int mRemainingSteps = -1;
63 
64     // Note that this is actually not equal to "mTotalSteps - mRemainingSteps", because the
65     // interface makes no promises about monotonically increasing by one each time.
66     private int mLocationsEnrolled = 0;
67 
68     @Nullable Listener mListener;
69 
UdfpsEnrollHelper(@onNull Context context, int reason)70     public UdfpsEnrollHelper(@NonNull Context context, int reason) {
71         mContext = context;
72         mEnrollReason = reason;
73 
74         final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
75         mAccessibilityEnabled = am.isEnabled();
76 
77         mGuidedEnrollmentPoints = new ArrayList<>();
78 
79         // Number of pixels per mm
80         float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1,
81                 context.getResources().getDisplayMetrics());
82         boolean useNewCoords = Settings.Secure.getIntForUser(mContext.getContentResolver(),
83                 NEW_COORDS_OVERRIDE, 0,
84                 UserHandle.USER_CURRENT) != 0;
85         if (useNewCoords && (Build.IS_ENG || Build.IS_USERDEBUG)) {
86             Log.v(TAG, "Using new coordinates");
87             mGuidedEnrollmentPoints.add(new PointF(-0.15f * px, -1.02f * px));
88             mGuidedEnrollmentPoints.add(new PointF(-0.15f * px,  1.02f * px));
89             mGuidedEnrollmentPoints.add(new PointF( 0.29f * px,  0.00f * px));
90             mGuidedEnrollmentPoints.add(new PointF( 2.17f * px, -2.35f * px));
91             mGuidedEnrollmentPoints.add(new PointF( 1.07f * px, -3.96f * px));
92             mGuidedEnrollmentPoints.add(new PointF(-0.37f * px, -4.31f * px));
93             mGuidedEnrollmentPoints.add(new PointF(-1.69f * px, -3.29f * px));
94             mGuidedEnrollmentPoints.add(new PointF(-2.48f * px, -1.23f * px));
95             mGuidedEnrollmentPoints.add(new PointF(-2.48f * px,  1.23f * px));
96             mGuidedEnrollmentPoints.add(new PointF(-1.69f * px,  3.29f * px));
97             mGuidedEnrollmentPoints.add(new PointF(-0.37f * px,  4.31f * px));
98             mGuidedEnrollmentPoints.add(new PointF( 1.07f * px,  3.96f * px));
99             mGuidedEnrollmentPoints.add(new PointF( 2.17f * px,  2.35f * px));
100             mGuidedEnrollmentPoints.add(new PointF( 2.58f * px,  0.00f * px));
101         } else {
102             Log.v(TAG, "Using old coordinates");
103             mGuidedEnrollmentPoints.add(new PointF( 2.00f * px,  0.00f * px));
104             mGuidedEnrollmentPoints.add(new PointF( 0.87f * px, -2.70f * px));
105             mGuidedEnrollmentPoints.add(new PointF(-1.80f * px, -1.31f * px));
106             mGuidedEnrollmentPoints.add(new PointF(-1.80f * px,  1.31f * px));
107             mGuidedEnrollmentPoints.add(new PointF( 0.88f * px,  2.70f * px));
108             mGuidedEnrollmentPoints.add(new PointF( 3.94f * px, -1.06f * px));
109             mGuidedEnrollmentPoints.add(new PointF( 2.90f * px, -4.14f * px));
110             mGuidedEnrollmentPoints.add(new PointF(-0.52f * px, -5.95f * px));
111             mGuidedEnrollmentPoints.add(new PointF(-3.33f * px, -3.33f * px));
112             mGuidedEnrollmentPoints.add(new PointF(-3.99f * px, -0.35f * px));
113             mGuidedEnrollmentPoints.add(new PointF(-3.62f * px,  2.54f * px));
114             mGuidedEnrollmentPoints.add(new PointF(-1.49f * px,  5.57f * px));
115             mGuidedEnrollmentPoints.add(new PointF( 2.29f * px,  4.92f * px));
116             mGuidedEnrollmentPoints.add(new PointF( 3.82f * px,  1.78f * px));
117         }
118     }
119 
shouldShowProgressBar()120     boolean shouldShowProgressBar() {
121         return mEnrollReason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING;
122     }
123 
onEnrollmentProgress(int remaining)124     void onEnrollmentProgress(int remaining) {
125         if (mTotalSteps == -1) {
126             mTotalSteps = remaining;
127         }
128 
129         if (remaining != mRemainingSteps) {
130             mLocationsEnrolled++;
131         }
132 
133         mRemainingSteps = remaining;
134 
135         if (mListener != null) {
136             mListener.onEnrollmentProgress(remaining, mTotalSteps);
137         }
138     }
139 
onEnrollmentHelp()140     void onEnrollmentHelp() {
141 
142     }
143 
setListener(Listener listener)144     void setListener(Listener listener) {
145         mListener = listener;
146 
147         // Only notify during setListener if enrollment is already in progress, so the progress
148         // bar can be updated. If enrollment has not started yet, the progress bar will be empty
149         // anyway.
150         if (mListener != null && mTotalSteps != -1) {
151             mListener.onEnrollmentProgress(mRemainingSteps, mTotalSteps);
152         }
153     }
154 
isCenterEnrollmentComplete()155     boolean isCenterEnrollmentComplete() {
156         if (mTotalSteps == -1 || mRemainingSteps == -1) {
157             return false;
158         } else if (mAccessibilityEnabled) {
159             return false;
160         }
161         final int stepsEnrolled = mTotalSteps - mRemainingSteps;
162         return stepsEnrolled >= NUM_CENTER_TOUCHES;
163     }
164 
165     @NonNull
getNextGuidedEnrollmentPoint()166     PointF getNextGuidedEnrollmentPoint() {
167         if (mAccessibilityEnabled) {
168             return new PointF(0f, 0f);
169         }
170 
171         float scale = SCALE;
172         if (Build.IS_ENG || Build.IS_USERDEBUG) {
173             scale = Settings.Secure.getFloatForUser(mContext.getContentResolver(),
174                     SCALE_OVERRIDE, SCALE,
175                     UserHandle.USER_CURRENT);
176         }
177         final int index = mLocationsEnrolled - NUM_CENTER_TOUCHES;
178         final PointF originalPoint = mGuidedEnrollmentPoints
179                 .get(index % mGuidedEnrollmentPoints.size());
180         return new PointF(originalPoint.x * scale, originalPoint.y * scale);
181     }
182 
animateIfLastStep()183     void animateIfLastStep() {
184         if (mListener == null) {
185             Log.e(TAG, "animateIfLastStep, null listener");
186             return;
187         }
188 
189         if (mRemainingSteps <= 2 && mRemainingSteps >= 0) {
190             mListener.onLastStepAcquired();
191         }
192     }
193 }
194