Move fingerprint authentication to a sidecar

It's possible for this sequence of events to occur
1) touch FPS
2) rotate device
3) authentication succeed message goes to pre-rotated activity
The pre-rotated activity will continue authenticating, and the fragment
will not highlight correctly upon authentication

Fixes: 63907591

Test: manual test of above condition, looks to be fixed

Test: rapidly tapping FPS while rotating works as expected

Change-Id: Ic830016f8bf52f926681110fcd908619ffc9dd31
This commit is contained in:
Kevin Chyn
2017-09-26 12:54:08 -07:00
parent 8caf1ff929
commit b8cfec8da1
2 changed files with 172 additions and 37 deletions

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 2017 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.fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.os.CancellationSignal;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.core.InstrumentedPreferenceFragment;
/**
* Sidecar fragment to handle the state around fingerprint authentication
*/
public class FingerprintAuthenticateSidecar extends InstrumentedPreferenceFragment {
private static final String TAG = "FingerprintAuthenticateSidecar";
private FingerprintManager mFingerprintManager;
private Listener mListener;
private AuthenticationResult mAuthenticationResult;
private CancellationSignal mCancellationSignal;
private AuthenticationError mAuthenticationError;
public interface Listener {
void onAuthenticationSucceeded(AuthenticationResult result);
void onAuthenticationFailed();
void onAuthenticationError(int errMsgId, CharSequence errString);
void onAuthenticationHelp(int helpMsgId, CharSequence helpString);
}
private class AuthenticationError {
int error;
CharSequence errorString;
public AuthenticationError(int errMsgId, CharSequence errString) {
error = errMsgId;
errorString = errString;
}
}
@Override
public int getMetricsCategory() {
return MetricsEvent.FINGERPRINT_AUTHENTICATE_SIDECAR;
}
private FingerprintManager.AuthenticationCallback mAuthenticationCallback =
new FingerprintManager.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(AuthenticationResult result) {
mCancellationSignal = null;
if (mListener != null) {
mListener.onAuthenticationSucceeded(result);
} else {
mAuthenticationResult = result;
mAuthenticationError = null;
}
}
@Override
public void onAuthenticationFailed() {
if (mListener != null) {
mListener.onAuthenticationFailed();
}
}
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
mCancellationSignal = null;
if (mListener != null) {
mListener.onAuthenticationError(errMsgId, errString);
} else {
mAuthenticationError = new AuthenticationError(errMsgId, errString);
mAuthenticationResult = null;
}
}
@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
if (mListener != null) {
mListener.onAuthenticationHelp(helpMsgId, helpString);
}
}
};
public void setFingerprintManager(FingerprintManager fingerprintManager) {
mFingerprintManager = fingerprintManager;
}
public void startAuthentication(int userId) {
mCancellationSignal = new CancellationSignal();
mFingerprintManager.authenticate(null, mCancellationSignal, 0 /* flags */,
mAuthenticationCallback, null, userId);
}
public void stopAuthentication() {
if (mCancellationSignal != null && !mCancellationSignal.isCanceled()) {
mCancellationSignal.cancel();
}
mCancellationSignal = null;
}
public void setListener(Listener listener) {
if (mListener == null && listener != null) {
if (mAuthenticationResult != null) {
mListener.onAuthenticationSucceeded(mAuthenticationResult);
mAuthenticationResult = null;
}
if (mAuthenticationError != null &&
mAuthenticationError.error != FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
mListener.onAuthenticationError(mAuthenticationError.error,
mAuthenticationError.errorString);
mAuthenticationError = null;
}
}
mListener = listener;
}
}

View File

@@ -29,8 +29,6 @@ import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -152,20 +150,23 @@ public class FingerprintSettings extends SubSettings {
protected static final boolean DEBUG = true;
private FingerprintManager mFingerprintManager;
private CancellationSignal mFingerprintCancel;
private boolean mInFingerprintLockout;
private byte[] mToken;
private boolean mLaunchedConfirm;
private Drawable mHighlightDrawable;
private int mUserId;
private static final String TAG_AUTHENTICATE_SIDECAR = "authenticate_sidecar";
private static final String TAG_REMOVAL_SIDECAR = "removal_sidecar";
private FingerprintAuthenticateSidecar mAuthenticateSidecar;
private FingerprintRemoveSidecar mRemovalSidecar;
private HashMap<Integer, String> mFingerprintsRenaming;
private AuthenticationCallback mAuthCallback = new AuthenticationCallback() {
FingerprintAuthenticateSidecar.Listener mAuthenticateListener =
new FingerprintAuthenticateSidecar.Listener() {
@Override
public void onAuthenticationSucceeded(AuthenticationResult result) {
public void onAuthenticationSucceeded(
FingerprintManager.AuthenticationResult result) {
int fingerId = result.getFingerprint().getFingerId();
mHandler.obtainMessage(MSG_FINGER_AUTH_SUCCESS, fingerId, 0).sendToTarget();
}
@@ -223,7 +224,6 @@ public class FingerprintSettings extends SubSettings {
retryFingerprint();
break;
case MSG_FINGER_AUTH_SUCCESS:
mFingerprintCancel = null;
highlightFingerprintItem(msg.arg1);
retryFingerprint();
break;
@@ -241,18 +241,10 @@ public class FingerprintSettings extends SubSettings {
}
};
private void stopFingerprint() {
if (mFingerprintCancel != null && !mFingerprintCancel.isCanceled()) {
mFingerprintCancel.cancel();
}
mFingerprintCancel = null;
}
/**
* @param errMsgId
*/
protected void handleError(int errMsgId, CharSequence msg) {
mFingerprintCancel = null;
switch (errMsgId) {
case FingerprintManager.FINGERPRINT_ERROR_CANCELED:
return; // Only happens if we get preempted by another activity. Ignored.
@@ -290,9 +282,8 @@ public class FingerprintSettings extends SubSettings {
return;
}
if (!mInFingerprintLockout) {
mFingerprintCancel = new CancellationSignal();
mFingerprintManager.authenticate(null, mFingerprintCancel, 0 /* flags */,
mAuthCallback, null, mUserId);
mAuthenticateSidecar.startAuthentication(mUserId);
mAuthenticateSidecar.setListener(mAuthenticateListener);
}
}
@@ -308,6 +299,15 @@ public class FingerprintSettings extends SubSettings {
Activity activity = getActivity();
mFingerprintManager = Utils.getFingerprintManagerOrNull(activity);
mAuthenticateSidecar = (FingerprintAuthenticateSidecar)
getFragmentManager().findFragmentByTag(TAG_AUTHENTICATE_SIDECAR);
if (mAuthenticateSidecar == null) {
mAuthenticateSidecar = new FingerprintAuthenticateSidecar();
getFragmentManager().beginTransaction()
.add(mAuthenticateSidecar, TAG_AUTHENTICATE_SIDECAR).commit();
}
mAuthenticateSidecar.setFingerprintManager(mFingerprintManager);
mRemovalSidecar = (FingerprintRemoveSidecar)
getFragmentManager().findFragmentByTag(TAG_REMOVAL_SIDECAR);
if (mRemovalSidecar == null) {
@@ -454,10 +454,13 @@ public class FingerprintSettings extends SubSettings {
@Override
public void onPause() {
super.onPause();
stopFingerprint();
if (mRemovalSidecar != null) {
mRemovalSidecar.setListener(null);
}
if (mAuthenticateSidecar != null) {
mAuthenticateSidecar.setListener(null);
mAuthenticateSidecar.stopAuthentication();
}
}
@Override