blob: cedbec1a0acacbed1ce0966c7dabed0b058873b3 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.settings.biometrics;
import android.annotation.Nullable;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.UserHandle;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.password.ChooseLockSettingsHelper;
import java.util.ArrayList;
/**
* Abstract sidecar fragment to handle the state around biometric enrollment. This sidecar manages
* the state of enrollment throughout the activity lifecycle so the app can continue after an
* event like rotation.
*/
public abstract class BiometricEnrollSidecar extends InstrumentedFragment {
public interface Listener {
void onEnrollmentHelp(int helpMsgId, CharSequence helpString);
void onEnrollmentError(int errMsgId, CharSequence errString);
void onEnrollmentProgressChange(int steps, int remaining);
}
private int mEnrollmentSteps = -1;
private int mEnrollmentRemaining = 0;
private Listener mListener;
private boolean mEnrolling;
private Handler mHandler = new Handler();
private boolean mDone;
private ArrayList<QueuedEvent> mQueuedEvents;
protected CancellationSignal mEnrollmentCancel;
protected byte[] mToken;
protected int mUserId;
private abstract class QueuedEvent {
public abstract void send(Listener listener);
}
private class QueuedEnrollmentProgress extends QueuedEvent {
int enrollmentSteps;
int remaining;
public QueuedEnrollmentProgress(int enrollmentSteps, int remaining) {
this.enrollmentSteps = enrollmentSteps;
this.remaining = remaining;
}
@Override
public void send(Listener listener) {
listener.onEnrollmentProgressChange(enrollmentSteps, remaining);
}
}
private class QueuedEnrollmentHelp extends QueuedEvent {
int helpMsgId;
CharSequence helpString;
public QueuedEnrollmentHelp(int helpMsgId, CharSequence helpString) {
this.helpMsgId = helpMsgId;
this.helpString = helpString;
}
@Override
public void send(Listener listener) {
listener.onEnrollmentHelp(helpMsgId, helpString);
}
}
private class QueuedEnrollmentError extends QueuedEvent {
int errMsgId;
CharSequence errString;
public QueuedEnrollmentError(int errMsgId, CharSequence errString) {
this.errMsgId = errMsgId;
this.errString = errString;
}
@Override
public void send(Listener listener) {
listener.onEnrollmentError(errMsgId, errString);
}
}
private final Runnable mTimeoutRunnable = new Runnable() {
@Override
public void run() {
cancelEnrollment();
}
};
public BiometricEnrollSidecar() {
mQueuedEvents = new ArrayList<>();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mToken = activity.getIntent().getByteArrayExtra(
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
mUserId = activity.getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
}
@Override
public void onStart() {
super.onStart();
if (!mEnrolling) {
startEnrollment();
}
}
@Override
public void onStop() {
super.onStop();
if (!getActivity().isChangingConfigurations()) {
cancelEnrollment();
}
}
protected void startEnrollment() {
mHandler.removeCallbacks(mTimeoutRunnable);
mEnrollmentSteps = -1;
mEnrollmentCancel = new CancellationSignal();
mEnrolling = true;
}
public boolean cancelEnrollment() {
mHandler.removeCallbacks(mTimeoutRunnable);
if (mEnrolling) {
mEnrollmentCancel.cancel();
mEnrolling = false;
mEnrollmentSteps = -1;
return true;
}
return false;
}
protected void onEnrollmentProgress(int remaining) {
if (mEnrollmentSteps == -1) {
mEnrollmentSteps = remaining;
}
mEnrollmentRemaining = remaining;
mDone = remaining == 0;
if (mListener != null) {
mListener.onEnrollmentProgressChange(mEnrollmentSteps, remaining);
} else {
mQueuedEvents.add(new QueuedEnrollmentProgress(mEnrollmentSteps, remaining));
}
}
protected void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
if (mListener != null) {
mListener.onEnrollmentHelp(helpMsgId, helpString);
} else {
mQueuedEvents.add(new QueuedEnrollmentHelp(helpMsgId, helpString));
}
}
protected void onEnrollmentError(int errMsgId, CharSequence errString) {
if (mListener != null) {
mListener.onEnrollmentError(errMsgId, errString);
} else {
mQueuedEvents.add(new QueuedEnrollmentError(errMsgId, errString));
}
mEnrolling = false;
}
public void setListener(Listener listener) {
mListener = listener;
if (mListener != null) {
for (int i=0; i<mQueuedEvents.size(); i++) {
QueuedEvent event = mQueuedEvents.get(i);
event.send(mListener);
}
mQueuedEvents.clear();
}
}
public int getEnrollmentSteps() {
return mEnrollmentSteps;
}
public int getEnrollmentRemaining() {
return mEnrollmentRemaining;
}
public boolean isDone() {
return mDone;
}
public boolean isEnrolling() {
return mEnrolling;
}
}