1 /* 2 * Copyright (C) 2015 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.fingerprint; 18 19 import android.annotation.Nullable; 20 import android.app.Activity; 21 import android.content.Intent; 22 import android.hardware.fingerprint.FingerprintManager; 23 import android.os.Bundle; 24 import android.os.CancellationSignal; 25 import android.os.Handler; 26 import android.os.UserHandle; 27 28 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 29 import com.android.settings.ChooseLockSettingsHelper; 30 import com.android.settings.Utils; 31 import com.android.settings.core.InstrumentedFragment; 32 import com.android.settings.password.IFingerprintManager; 33 34 import java.util.ArrayList; 35 36 /** 37 * Sidecar fragment to handle the state around fingerprint enrollment. 38 */ 39 public class FingerprintEnrollSidecar extends InstrumentedFragment { 40 41 private int mEnrollmentSteps = -1; 42 private int mEnrollmentRemaining = 0; 43 private Listener mListener; 44 private boolean mEnrolling; 45 private CancellationSignal mEnrollmentCancel; 46 private Handler mHandler = new Handler(); 47 private byte[] mToken; 48 private boolean mDone; 49 private int mUserId; 50 private IFingerprintManager mFingerprintManager; 51 private ArrayList<QueuedEvent> mQueuedEvents; 52 53 private abstract class QueuedEvent { send(Listener listener)54 public abstract void send(Listener listener); 55 } 56 57 private class QueuedEnrollmentProgress extends QueuedEvent { 58 int enrollmentSteps; 59 int remaining; QueuedEnrollmentProgress(int enrollmentSteps, int remaining)60 public QueuedEnrollmentProgress(int enrollmentSteps, int remaining) { 61 this.enrollmentSteps = enrollmentSteps; 62 this.remaining = remaining; 63 } 64 65 @Override send(Listener listener)66 public void send(Listener listener) { 67 listener.onEnrollmentProgressChange(enrollmentSteps, remaining); 68 } 69 } 70 71 private class QueuedEnrollmentHelp extends QueuedEvent { 72 int helpMsgId; 73 CharSequence helpString; QueuedEnrollmentHelp(int helpMsgId, CharSequence helpString)74 public QueuedEnrollmentHelp(int helpMsgId, CharSequence helpString) { 75 this.helpMsgId = helpMsgId; 76 this.helpString = helpString; 77 } 78 79 @Override send(Listener listener)80 public void send(Listener listener) { 81 listener.onEnrollmentHelp(helpString); 82 } 83 } 84 85 private class QueuedEnrollmentError extends QueuedEvent { 86 int errMsgId; 87 CharSequence errString; QueuedEnrollmentError(int errMsgId, CharSequence errString)88 public QueuedEnrollmentError(int errMsgId, CharSequence errString) { 89 this.errMsgId = errMsgId; 90 this.errString = errString; 91 } 92 93 @Override send(Listener listener)94 public void send(Listener listener) { 95 listener.onEnrollmentError(errMsgId, errString); 96 } 97 } 98 FingerprintEnrollSidecar()99 public FingerprintEnrollSidecar() { 100 mQueuedEvents = new ArrayList<>(); 101 } 102 103 @Override onCreate(@ullable Bundle savedInstanceState)104 public void onCreate(@Nullable Bundle savedInstanceState) { 105 super.onCreate(savedInstanceState); 106 setRetainInstance(true); 107 } 108 109 @Override onAttach(Activity activity)110 public void onAttach(Activity activity) { 111 super.onAttach(activity); 112 mFingerprintManager = Utils.getFingerprintManagerWrapperOrNull(activity); 113 mToken = activity.getIntent().getByteArrayExtra( 114 ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); 115 mUserId = activity.getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL); 116 } 117 118 @Override onStart()119 public void onStart() { 120 super.onStart(); 121 if (!mEnrolling) { 122 startEnrollment(); 123 } 124 } 125 126 @Override onStop()127 public void onStop() { 128 super.onStop(); 129 if (!getActivity().isChangingConfigurations()) { 130 cancelEnrollment(); 131 } 132 } 133 startEnrollment()134 private void startEnrollment() { 135 mHandler.removeCallbacks(mTimeoutRunnable); 136 mEnrollmentSteps = -1; 137 mEnrollmentCancel = new CancellationSignal(); 138 if (mUserId != UserHandle.USER_NULL) { 139 mFingerprintManager.setActiveUser(mUserId); 140 } 141 mFingerprintManager.enroll(mToken, mEnrollmentCancel, 142 0 /* flags */, mUserId, mEnrollmentCallback); 143 mEnrolling = true; 144 } 145 cancelEnrollment()146 boolean cancelEnrollment() { 147 mHandler.removeCallbacks(mTimeoutRunnable); 148 if (mEnrolling) { 149 mEnrollmentCancel.cancel(); 150 mEnrolling = false; 151 mEnrollmentSteps = -1; 152 return true; 153 } 154 return false; 155 } 156 setListener(Listener listener)157 public void setListener(Listener listener) { 158 mListener = listener; 159 if (mListener != null) { 160 for (int i=0; i<mQueuedEvents.size(); i++) { 161 QueuedEvent event = mQueuedEvents.get(i); 162 event.send(mListener); 163 } 164 mQueuedEvents.clear(); 165 } 166 } 167 getEnrollmentSteps()168 public int getEnrollmentSteps() { 169 return mEnrollmentSteps; 170 } 171 getEnrollmentRemaining()172 public int getEnrollmentRemaining() { 173 return mEnrollmentRemaining; 174 } 175 isDone()176 public boolean isDone() { 177 return mDone; 178 } 179 180 private FingerprintManager.EnrollmentCallback mEnrollmentCallback 181 = new FingerprintManager.EnrollmentCallback() { 182 183 @Override 184 public void onEnrollmentProgress(int remaining) { 185 if (mEnrollmentSteps == -1) { 186 mEnrollmentSteps = remaining; 187 } 188 mEnrollmentRemaining = remaining; 189 mDone = remaining == 0; 190 if (mListener != null) { 191 mListener.onEnrollmentProgressChange(mEnrollmentSteps, remaining); 192 } else { 193 mQueuedEvents.add(new QueuedEnrollmentProgress(mEnrollmentSteps, remaining)); 194 } 195 } 196 197 @Override 198 public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { 199 if (mListener != null) { 200 mListener.onEnrollmentHelp(helpString); 201 } else { 202 mQueuedEvents.add(new QueuedEnrollmentHelp(helpMsgId, helpString)); 203 } 204 } 205 206 @Override 207 public void onEnrollmentError(int errMsgId, CharSequence errString) { 208 if (mListener != null) { 209 mListener.onEnrollmentError(errMsgId, errString); 210 } else { 211 mQueuedEvents.add(new QueuedEnrollmentError(errMsgId, errString)); 212 } 213 mEnrolling = false; 214 } 215 }; 216 217 private final Runnable mTimeoutRunnable = new Runnable() { 218 @Override 219 public void run() { 220 cancelEnrollment(); 221 } 222 }; 223 224 @Override getMetricsCategory()225 public int getMetricsCategory() { 226 return MetricsEvent.FINGERPRINT_ENROLL_SIDECAR; 227 } 228 229 public interface Listener { onEnrollmentHelp(CharSequence helpString)230 void onEnrollmentHelp(CharSequence helpString); onEnrollmentError(int errMsgId, CharSequence errString)231 void onEnrollmentError(int errMsgId, CharSequence errString); onEnrollmentProgressChange(int steps, int remaining)232 void onEnrollmentProgressChange(int steps, int remaining); 233 } 234 isEnrolling()235 public boolean isEnrolling() { 236 return mEnrolling; 237 } 238 } 239