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