Merge "Do not clear calling identify when using BiometricPrompt from FingerprintService." into tm-dev
This commit is contained in:
@@ -421,6 +421,18 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if BiometricPrompt is being used by the legacy fingerprint manager API.
|
||||||
|
* @param sensorId sensor id
|
||||||
|
* @return This builder.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Builder setIsForLegacyFingerprintManager(int sensorId) {
|
||||||
|
mPromptInfo.setIsForLegacyFingerprintManager(sensorId);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link BiometricPrompt}.
|
* Creates a {@link BiometricPrompt}.
|
||||||
*
|
*
|
||||||
@@ -883,28 +895,36 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
@NonNull @CallbackExecutor Executor executor,
|
@NonNull @CallbackExecutor Executor executor,
|
||||||
@NonNull AuthenticationCallback callback,
|
@NonNull AuthenticationCallback callback,
|
||||||
int userId) {
|
int userId) {
|
||||||
authenticateUserForOperation(cancel, executor, callback, userId, 0 /* operationId */);
|
if (cancel == null) {
|
||||||
|
throw new IllegalArgumentException("Must supply a cancellation signal");
|
||||||
|
}
|
||||||
|
if (executor == null) {
|
||||||
|
throw new IllegalArgumentException("Must supply an executor");
|
||||||
|
}
|
||||||
|
if (callback == null) {
|
||||||
|
throw new IllegalArgumentException("Must supply a callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticateInternal(0 /* operationId */, cancel, executor, callback, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates for the given user and keystore operation.
|
* Authenticates for the given keystore operation.
|
||||||
*
|
*
|
||||||
* @param cancel An object that can be used to cancel authentication
|
* @param cancel An object that can be used to cancel authentication
|
||||||
* @param executor An executor to handle callback events
|
* @param executor An executor to handle callback events
|
||||||
* @param callback An object to receive authentication events
|
* @param callback An object to receive authentication events
|
||||||
* @param userId The user to authenticate
|
|
||||||
* @param operationId The keystore operation associated with authentication
|
* @param operationId The keystore operation associated with authentication
|
||||||
*
|
*
|
||||||
* @return A requestId that can be used to cancel this operation.
|
* @return A requestId that can be used to cancel this operation.
|
||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
@RequiresPermission(USE_BIOMETRIC)
|
||||||
public long authenticateUserForOperation(
|
public long authenticateForOperation(
|
||||||
@NonNull CancellationSignal cancel,
|
@NonNull CancellationSignal cancel,
|
||||||
@NonNull @CallbackExecutor Executor executor,
|
@NonNull @CallbackExecutor Executor executor,
|
||||||
@NonNull AuthenticationCallback callback,
|
@NonNull AuthenticationCallback callback,
|
||||||
int userId,
|
|
||||||
long operationId) {
|
long operationId) {
|
||||||
if (cancel == null) {
|
if (cancel == null) {
|
||||||
throw new IllegalArgumentException("Must supply a cancellation signal");
|
throw new IllegalArgumentException("Must supply a cancellation signal");
|
||||||
@@ -916,7 +936,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
throw new IllegalArgumentException("Must supply a callback");
|
throw new IllegalArgumentException("Must supply a callback");
|
||||||
}
|
}
|
||||||
|
|
||||||
return authenticateInternal(operationId, cancel, executor, callback, userId);
|
return authenticateInternal(operationId, cancel, executor, callback, mContext.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1050,7 +1070,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
private void cancelAuthentication(long requestId) {
|
private void cancelAuthentication(long requestId) {
|
||||||
if (mService != null) {
|
if (mService != null) {
|
||||||
try {
|
try {
|
||||||
mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
|
mService.cancelAuthentication(mToken, mContext.getPackageName(), requestId);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Unable to cancel authentication", e);
|
Log.e(TAG, "Unable to cancel authentication", e);
|
||||||
}
|
}
|
||||||
@@ -1109,7 +1129,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
}
|
}
|
||||||
|
|
||||||
final long authId = mService.authenticate(mToken, operationId, userId,
|
final long authId = mService.authenticate(mToken, operationId, userId,
|
||||||
mBiometricServiceReceiver, mContext.getOpPackageName(), promptInfo);
|
mBiometricServiceReceiver, mContext.getPackageName(), promptInfo);
|
||||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
|
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
|
||||||
return authId;
|
return authId;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package android.hardware.biometrics;
|
|||||||
* ITestSession callback for FingerprintManager and BiometricManager.
|
* ITestSession callback for FingerprintManager and BiometricManager.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
interface ITestSessionCallback {
|
oneway interface ITestSessionCallback {
|
||||||
void onCleanupStarted(int userId);
|
void onCleanupStarted(int userId);
|
||||||
void onCleanupFinished(int userId);
|
void onCleanupFinished(int userId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public class PromptInfo implements Parcelable {
|
|||||||
@NonNull private List<Integer> mAllowedSensorIds = new ArrayList<>();
|
@NonNull private List<Integer> mAllowedSensorIds = new ArrayList<>();
|
||||||
private boolean mAllowBackgroundAuthentication;
|
private boolean mAllowBackgroundAuthentication;
|
||||||
private boolean mIgnoreEnrollmentState;
|
private boolean mIgnoreEnrollmentState;
|
||||||
|
private boolean mIsForLegacyFingerprintManager = false;
|
||||||
|
|
||||||
public PromptInfo() {
|
public PromptInfo() {
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@ public class PromptInfo implements Parcelable {
|
|||||||
mAllowedSensorIds = in.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class);
|
mAllowedSensorIds = in.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class);
|
||||||
mAllowBackgroundAuthentication = in.readBoolean();
|
mAllowBackgroundAuthentication = in.readBoolean();
|
||||||
mIgnoreEnrollmentState = in.readBoolean();
|
mIgnoreEnrollmentState = in.readBoolean();
|
||||||
|
mIsForLegacyFingerprintManager = in.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
|
public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
|
||||||
@@ -105,10 +107,15 @@ public class PromptInfo implements Parcelable {
|
|||||||
dest.writeList(mAllowedSensorIds);
|
dest.writeList(mAllowedSensorIds);
|
||||||
dest.writeBoolean(mAllowBackgroundAuthentication);
|
dest.writeBoolean(mAllowBackgroundAuthentication);
|
||||||
dest.writeBoolean(mIgnoreEnrollmentState);
|
dest.writeBoolean(mIgnoreEnrollmentState);
|
||||||
|
dest.writeBoolean(mIsForLegacyFingerprintManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsTestConfigurations() {
|
public boolean containsTestConfigurations() {
|
||||||
if (!mAllowedSensorIds.isEmpty()) {
|
if (mIsForLegacyFingerprintManager
|
||||||
|
&& mAllowedSensorIds.size() == 1
|
||||||
|
&& !mAllowBackgroundAuthentication) {
|
||||||
|
return false;
|
||||||
|
} else if (!mAllowedSensorIds.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (mAllowBackgroundAuthentication) {
|
} else if (mAllowBackgroundAuthentication) {
|
||||||
return true;
|
return true;
|
||||||
@@ -188,7 +195,8 @@ public class PromptInfo implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setAllowedSensorIds(@NonNull List<Integer> sensorIds) {
|
public void setAllowedSensorIds(@NonNull List<Integer> sensorIds) {
|
||||||
mAllowedSensorIds = sensorIds;
|
mAllowedSensorIds.clear();
|
||||||
|
mAllowedSensorIds.addAll(sensorIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAllowBackgroundAuthentication(boolean allow) {
|
public void setAllowBackgroundAuthentication(boolean allow) {
|
||||||
@@ -199,6 +207,12 @@ public class PromptInfo implements Parcelable {
|
|||||||
mIgnoreEnrollmentState = ignoreEnrollmentState;
|
mIgnoreEnrollmentState = ignoreEnrollmentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setIsForLegacyFingerprintManager(int sensorId) {
|
||||||
|
mIsForLegacyFingerprintManager = true;
|
||||||
|
mAllowedSensorIds.clear();
|
||||||
|
mAllowedSensorIds.add(sensorId);
|
||||||
|
}
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
|
|
||||||
public CharSequence getTitle() {
|
public CharSequence getTitle() {
|
||||||
@@ -272,4 +286,8 @@ public class PromptInfo implements Parcelable {
|
|||||||
public boolean isIgnoreEnrollmentState() {
|
public boolean isIgnoreEnrollmentState() {
|
||||||
return mIgnoreEnrollmentState;
|
return mIgnoreEnrollmentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isForLegacyFingerprintManager() {
|
||||||
|
return mIsForLegacyFingerprintManager;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
|
|||||||
final TaskStackListener mTaskStackListener = new TaskStackListener() {
|
final TaskStackListener mTaskStackListener = new TaskStackListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onTaskStackChanged() {
|
public void onTaskStackChanged() {
|
||||||
mHandler.post(AuthController.this::handleTaskStackChanged);
|
mHandler.post(AuthController.this::cancelIfOwnerIsNotInForeground);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private void handleTaskStackChanged() {
|
private void cancelIfOwnerIsNotInForeground() {
|
||||||
mExecution.assertIsMainThread();
|
mExecution.assertIsMainThread();
|
||||||
if (mCurrentDialog != null) {
|
if (mCurrentDialog != null) {
|
||||||
try {
|
try {
|
||||||
@@ -212,7 +212,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
|
|||||||
final String topPackage = runningTasks.get(0).topActivity.getPackageName();
|
final String topPackage = runningTasks.get(0).topActivity.getPackageName();
|
||||||
if (!topPackage.contentEquals(clientPackage)
|
if (!topPackage.contentEquals(clientPackage)
|
||||||
&& !Utils.isSystem(mContext, clientPackage)) {
|
&& !Utils.isSystem(mContext, clientPackage)) {
|
||||||
Log.w(TAG, "Evicting client due to: " + topPackage);
|
Log.e(TAG, "Evicting client due to: " + topPackage);
|
||||||
mCurrentDialog.dismissWithoutCallback(true /* animate */);
|
mCurrentDialog.dismissWithoutCallback(true /* animate */);
|
||||||
mCurrentDialog = null;
|
mCurrentDialog = null;
|
||||||
mOrientationListener.disable();
|
mOrientationListener.disable();
|
||||||
@@ -919,6 +919,10 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
|
|||||||
mCurrentDialog = newDialog;
|
mCurrentDialog = newDialog;
|
||||||
mCurrentDialog.show(mWindowManager, savedState);
|
mCurrentDialog.show(mWindowManager, savedState);
|
||||||
mOrientationListener.enable();
|
mOrientationListener.enable();
|
||||||
|
|
||||||
|
if (!promptInfo.isAllowBackgroundAuthentication()) {
|
||||||
|
mHandler.post(this::cancelIfOwnerIsNotInForeground);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDialogDismissed(@DismissedReason int reason) {
|
private void onDialogDismissed(@DismissedReason int reason) {
|
||||||
|
|||||||
@@ -602,16 +602,26 @@ public class AuthControllerTest extends SysuiTestCase {
|
|||||||
mAuthController.mLastBiometricPromptInfo.getAuthenticators());
|
mAuthController.mLastBiometricPromptInfo.getAuthenticators());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientNotified_whenTaskStackChangesDuringShow() throws Exception {
|
||||||
|
switchTask("other_package");
|
||||||
|
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
|
||||||
|
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
|
|
||||||
|
assertNull(mAuthController.mCurrentDialog);
|
||||||
|
assertNull(mAuthController.mReceiver);
|
||||||
|
verify(mDialog1).dismissWithoutCallback(true /* animate */);
|
||||||
|
verify(mReceiver).onDialogDismissed(
|
||||||
|
eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL),
|
||||||
|
eq(null) /* credentialAttestation */);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClientNotified_whenTaskStackChangesDuringAuthentication() throws Exception {
|
public void testClientNotified_whenTaskStackChangesDuringAuthentication() throws Exception {
|
||||||
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
|
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
|
||||||
|
|
||||||
List<ActivityManager.RunningTaskInfo> tasks = new ArrayList<>();
|
switchTask("other_package");
|
||||||
ActivityManager.RunningTaskInfo taskInfo = mock(ActivityManager.RunningTaskInfo.class);
|
|
||||||
taskInfo.topActivity = mock(ComponentName.class);
|
|
||||||
when(taskInfo.topActivity.getPackageName()).thenReturn("other_package");
|
|
||||||
tasks.add(taskInfo);
|
|
||||||
when(mActivityTaskManager.getTasks(anyInt())).thenReturn(tasks);
|
|
||||||
|
|
||||||
mAuthController.mTaskStackListener.onTaskStackChanged();
|
mAuthController.mTaskStackListener.onTaskStackChanged();
|
||||||
mTestableLooper.processAllMessages();
|
mTestableLooper.processAllMessages();
|
||||||
@@ -729,6 +739,16 @@ public class AuthControllerTest extends SysuiTestCase {
|
|||||||
BIOMETRIC_MULTI_SENSOR_FINGERPRINT_AND_FACE);
|
BIOMETRIC_MULTI_SENSOR_FINGERPRINT_AND_FACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void switchTask(String packageName) {
|
||||||
|
final List<ActivityManager.RunningTaskInfo> tasks = new ArrayList<>();
|
||||||
|
final ActivityManager.RunningTaskInfo taskInfo =
|
||||||
|
mock(ActivityManager.RunningTaskInfo.class);
|
||||||
|
taskInfo.topActivity = mock(ComponentName.class);
|
||||||
|
when(taskInfo.topActivity.getPackageName()).thenReturn(packageName);
|
||||||
|
tasks.add(taskInfo);
|
||||||
|
when(mActivityTaskManager.getTasks(anyInt())).thenReturn(tasks);
|
||||||
|
}
|
||||||
|
|
||||||
private PromptInfo createTestPromptInfo() {
|
private PromptInfo createTestPromptInfo() {
|
||||||
PromptInfo promptInfo = new PromptInfo();
|
PromptInfo promptInfo = new PromptInfo();
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
|
|||||||
mIsStrongBiometric = isStrongBiometric;
|
mIsStrongBiometric = isStrongBiometric;
|
||||||
mOperationId = operationId;
|
mOperationId = operationId;
|
||||||
mRequireConfirmation = requireConfirmation;
|
mRequireConfirmation = requireConfirmation;
|
||||||
mActivityTaskManager = ActivityTaskManager.getInstance();
|
mActivityTaskManager = getActivityTaskManager();
|
||||||
mBiometricManager = context.getSystemService(BiometricManager.class);
|
mBiometricManager = context.getSystemService(BiometricManager.class);
|
||||||
mTaskStackListener = taskStackListener;
|
mTaskStackListener = taskStackListener;
|
||||||
mLockoutTracker = lockoutTracker;
|
mLockoutTracker = lockoutTracker;
|
||||||
@@ -133,6 +133,10 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
|
|||||||
return mStartTimeMs;
|
return mStartTimeMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ActivityTaskManager getActivityTaskManager() {
|
||||||
|
return ActivityTaskManager.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
final boolean clearListener = !isBiometricPrompt();
|
final boolean clearListener = !isBiometricPrompt();
|
||||||
@@ -310,45 +314,50 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
|
|||||||
sendCancelOnly(listener);
|
sendCancelOnly(listener);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else { // not authenticated
|
||||||
// Allow system-defined limit of number of attempts before giving up
|
if (isBackgroundAuth) {
|
||||||
final @LockoutTracker.LockoutMode int lockoutMode =
|
Slog.e(TAG, "cancelling due to background auth");
|
||||||
handleFailedAttempt(getTargetUserId());
|
cancel();
|
||||||
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
|
} else {
|
||||||
markAlreadyDone();
|
// Allow system-defined limit of number of attempts before giving up
|
||||||
|
final @LockoutTracker.LockoutMode int lockoutMode =
|
||||||
|
handleFailedAttempt(getTargetUserId());
|
||||||
|
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
|
||||||
|
markAlreadyDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
final CoexCoordinator coordinator = CoexCoordinator.getInstance();
|
||||||
|
coordinator.onAuthenticationRejected(SystemClock.uptimeMillis(), this, lockoutMode,
|
||||||
|
new CoexCoordinator.Callback() {
|
||||||
|
@Override
|
||||||
|
public void sendAuthenticationResult(boolean addAuthTokenIfStrong) {
|
||||||
|
if (listener != null) {
|
||||||
|
try {
|
||||||
|
listener.onAuthenticationFailed(getSensorId());
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG, "Unable to notify listener", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendHapticFeedback() {
|
||||||
|
if (listener != null && mShouldVibrate) {
|
||||||
|
vibrateError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleLifecycleAfterAuth() {
|
||||||
|
AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendAuthenticationCanceled() {
|
||||||
|
sendCancelOnly(listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final CoexCoordinator coordinator = CoexCoordinator.getInstance();
|
|
||||||
coordinator.onAuthenticationRejected(SystemClock.uptimeMillis(), this, lockoutMode,
|
|
||||||
new CoexCoordinator.Callback() {
|
|
||||||
@Override
|
|
||||||
public void sendAuthenticationResult(boolean addAuthTokenIfStrong) {
|
|
||||||
if (listener != null) {
|
|
||||||
try {
|
|
||||||
listener.onAuthenticationFailed(getSensorId());
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Slog.e(TAG, "Unable to notify listener", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendHapticFeedback() {
|
|
||||||
if (listener != null && mShouldVibrate) {
|
|
||||||
vibrateError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleLifecycleAfterAuth() {
|
|
||||||
AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendAuthenticationCanceled() {
|
|
||||||
sendCancelOnly(listener);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -344,12 +344,12 @@ public class FingerprintService extends SystemService {
|
|||||||
provider.second.getSensorProperties(sensorId);
|
provider.second.getSensorProperties(sensorId);
|
||||||
if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName)
|
if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName)
|
||||||
&& sensorProps != null && sensorProps.isAnyUdfpsType()) {
|
&& sensorProps != null && sensorProps.isAnyUdfpsType()) {
|
||||||
final long identity2 = Binder.clearCallingIdentity();
|
|
||||||
try {
|
try {
|
||||||
return authenticateWithPrompt(operationId, sensorProps, userId, receiver,
|
return authenticateWithPrompt(operationId, sensorProps, userId, receiver,
|
||||||
ignoreEnrollmentState);
|
opPackageName, ignoreEnrollmentState);
|
||||||
} finally {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
Binder.restoreCallingIdentity(identity2);
|
Slog.e(TAG, "Invalid package", e);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
|
return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
|
||||||
@@ -362,12 +362,15 @@ public class FingerprintService extends SystemService {
|
|||||||
@NonNull final FingerprintSensorPropertiesInternal props,
|
@NonNull final FingerprintSensorPropertiesInternal props,
|
||||||
final int userId,
|
final int userId,
|
||||||
final IFingerprintServiceReceiver receiver,
|
final IFingerprintServiceReceiver receiver,
|
||||||
boolean ignoreEnrollmentState) {
|
final String opPackageName,
|
||||||
|
boolean ignoreEnrollmentState) throws PackageManager.NameNotFoundException {
|
||||||
|
|
||||||
final Context context = getUiContext();
|
final Context context = getUiContext();
|
||||||
|
final Context promptContext = context.createPackageContextAsUser(
|
||||||
|
opPackageName, 0 /* flags */, UserHandle.getUserHandleForUid(userId));
|
||||||
final Executor executor = context.getMainExecutor();
|
final Executor executor = context.getMainExecutor();
|
||||||
|
|
||||||
final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(context)
|
final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(promptContext)
|
||||||
.setTitle(context.getString(R.string.biometric_dialog_default_title))
|
.setTitle(context.getString(R.string.biometric_dialog_default_title))
|
||||||
.setSubtitle(context.getString(R.string.fingerprint_dialog_default_subtitle))
|
.setSubtitle(context.getString(R.string.fingerprint_dialog_default_subtitle))
|
||||||
.setNegativeButton(
|
.setNegativeButton(
|
||||||
@@ -381,8 +384,7 @@ public class FingerprintService extends SystemService {
|
|||||||
Slog.e(TAG, "Remote exception in negative button onClick()", e);
|
Slog.e(TAG, "Remote exception in negative button onClick()", e);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setAllowedSensorIds(new ArrayList<>(
|
.setIsForLegacyFingerprintManager(props.sensorId)
|
||||||
Collections.singletonList(props.sensorId)))
|
|
||||||
.setIgnoreEnrollmentState(ignoreEnrollmentState)
|
.setIgnoreEnrollmentState(ignoreEnrollmentState)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -436,8 +438,8 @@ public class FingerprintService extends SystemService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return biometricPrompt.authenticateUserForOperation(
|
return biometricPrompt.authenticateForOperation(
|
||||||
new CancellationSignal(), executor, promptCallback, userId, operationId);
|
new CancellationSignal(), executor, promptCallback, operationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.face.aidl;
|
|||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.inOrder;
|
||||||
@@ -26,8 +27,13 @@ import static org.mockito.Mockito.same;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.ActivityTaskManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.hardware.biometrics.common.ICancellationSignal;
|
||||||
import android.hardware.biometrics.common.OperationContext;
|
import android.hardware.biometrics.common.OperationContext;
|
||||||
import android.hardware.biometrics.face.ISession;
|
import android.hardware.biometrics.face.ISession;
|
||||||
|
import android.hardware.face.Face;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
@@ -53,6 +59,9 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.junit.MockitoJUnit;
|
import org.mockito.junit.MockitoJUnit;
|
||||||
import org.mockito.junit.MockitoRule;
|
import org.mockito.junit.MockitoRule;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Presubmit
|
@Presubmit
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public class FaceAuthenticationClientTest {
|
public class FaceAuthenticationClientTest {
|
||||||
@@ -82,6 +91,10 @@ public class FaceAuthenticationClientTest {
|
|||||||
private ClientMonitorCallback mCallback;
|
private ClientMonitorCallback mCallback;
|
||||||
@Mock
|
@Mock
|
||||||
private Sensor.HalSessionCallback mHalSessionCallback;
|
private Sensor.HalSessionCallback mHalSessionCallback;
|
||||||
|
@Mock
|
||||||
|
private ActivityTaskManager mActivityTaskManager;
|
||||||
|
@Mock
|
||||||
|
private ICancellationSignal mCancellationSignal;
|
||||||
@Captor
|
@Captor
|
||||||
private ArgumentCaptor<OperationContext> mOperationContextCaptor;
|
private ArgumentCaptor<OperationContext> mOperationContextCaptor;
|
||||||
|
|
||||||
@@ -116,6 +129,25 @@ public class FaceAuthenticationClientTest {
|
|||||||
verify(mHal, never()).authenticate(anyLong());
|
verify(mHal, never()).authenticate(anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cancelsAuthWhenNotInForeground() throws Exception {
|
||||||
|
final ActivityManager.RunningTaskInfo topTask = new ActivityManager.RunningTaskInfo();
|
||||||
|
topTask.topActivity = new ComponentName("other", "thing");
|
||||||
|
when(mActivityTaskManager.getTasks(anyInt())).thenReturn(List.of(topTask));
|
||||||
|
when(mHal.authenticateWithContext(anyLong(), any())).thenReturn(mCancellationSignal);
|
||||||
|
|
||||||
|
final FaceAuthenticationClient client = createClient();
|
||||||
|
client.start(mCallback);
|
||||||
|
client.onAuthenticated(new Face("friendly", 1 /* faceId */, 2 /* deviceId */),
|
||||||
|
true /* authenticated */, new ArrayList<>());
|
||||||
|
|
||||||
|
verify(mCancellationSignal).cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FaceAuthenticationClient createClient() throws RemoteException {
|
||||||
|
return createClient(2 /* version */);
|
||||||
|
}
|
||||||
|
|
||||||
private FaceAuthenticationClient createClient(int version) throws RemoteException {
|
private FaceAuthenticationClient createClient(int version) throws RemoteException {
|
||||||
when(mHal.getInterfaceVersion()).thenReturn(version);
|
when(mHal.getInterfaceVersion()).thenReturn(version);
|
||||||
|
|
||||||
@@ -126,6 +158,11 @@ public class FaceAuthenticationClientTest {
|
|||||||
false /* requireConfirmation */, 9 /* sensorId */,
|
false /* requireConfirmation */, 9 /* sensorId */,
|
||||||
mBiometricLogger, mBiometricContext, true /* isStrongBiometric */,
|
mBiometricLogger, mBiometricContext, true /* isStrongBiometric */,
|
||||||
mUsageStats, mLockoutCache, false /* allowBackgroundAuthentication */,
|
mUsageStats, mLockoutCache, false /* allowBackgroundAuthentication */,
|
||||||
false /* isKeyguardBypassEnabled */, null /* sensorPrivacyManager */);
|
false /* isKeyguardBypassEnabled */, null /* sensorPrivacyManager */) {
|
||||||
|
@Override
|
||||||
|
protected ActivityTaskManager getActivityTaskManager() {
|
||||||
|
return mActivityTaskManager;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ import static org.mockito.Mockito.times;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.ActivityTaskManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.hardware.biometrics.BiometricManager;
|
import android.hardware.biometrics.BiometricManager;
|
||||||
|
import android.hardware.biometrics.common.ICancellationSignal;
|
||||||
import android.hardware.biometrics.common.OperationContext;
|
import android.hardware.biometrics.common.OperationContext;
|
||||||
import android.hardware.biometrics.fingerprint.ISession;
|
import android.hardware.biometrics.fingerprint.ISession;
|
||||||
import android.hardware.biometrics.fingerprint.PointerContext;
|
import android.hardware.biometrics.fingerprint.PointerContext;
|
||||||
@@ -66,6 +70,7 @@ import org.mockito.junit.MockitoJUnit;
|
|||||||
import org.mockito.junit.MockitoRule;
|
import org.mockito.junit.MockitoRule;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@Presubmit
|
@Presubmit
|
||||||
@@ -111,6 +116,10 @@ public class FingerprintAuthenticationClientTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private Sensor.HalSessionCallback mHalSessionCallback;
|
private Sensor.HalSessionCallback mHalSessionCallback;
|
||||||
@Mock
|
@Mock
|
||||||
|
private ActivityTaskManager mActivityTaskManager;
|
||||||
|
@Mock
|
||||||
|
private ICancellationSignal mCancellationSignal;
|
||||||
|
@Mock
|
||||||
private Probe mLuxProbe;
|
private Probe mLuxProbe;
|
||||||
@Captor
|
@Captor
|
||||||
private ArgumentCaptor<OperationContext> mOperationContextCaptor;
|
private ArgumentCaptor<OperationContext> mOperationContextCaptor;
|
||||||
@@ -288,11 +297,36 @@ public class FingerprintAuthenticationClientTest {
|
|||||||
verify(mSideFpsController).hide(anyInt());
|
verify(mSideFpsController).hide(anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cancelsAuthWhenNotInForeground() throws Exception {
|
||||||
|
final ActivityManager.RunningTaskInfo topTask = new ActivityManager.RunningTaskInfo();
|
||||||
|
topTask.topActivity = new ComponentName("other", "thing");
|
||||||
|
when(mActivityTaskManager.getTasks(anyInt())).thenReturn(List.of(topTask));
|
||||||
|
when(mHal.authenticateWithContext(anyLong(), any())).thenReturn(mCancellationSignal);
|
||||||
|
|
||||||
|
final FingerprintAuthenticationClient client = createClientWithoutBackgroundAuth();
|
||||||
|
client.start(mCallback);
|
||||||
|
client.onAuthenticated(new Fingerprint("friendly", 1 /* fingerId */, 2 /* deviceId */),
|
||||||
|
true /* authenticated */, new ArrayList<>());
|
||||||
|
|
||||||
|
verify(mCancellationSignal).cancel();
|
||||||
|
}
|
||||||
|
|
||||||
private FingerprintAuthenticationClient createClient() throws RemoteException {
|
private FingerprintAuthenticationClient createClient() throws RemoteException {
|
||||||
return createClient(100);
|
return createClient(100 /* version */, true /* allowBackgroundAuthentication */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FingerprintAuthenticationClient createClientWithoutBackgroundAuth()
|
||||||
|
throws RemoteException {
|
||||||
|
return createClient(100 /* version */, false /* allowBackgroundAuthentication */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private FingerprintAuthenticationClient createClient(int version) throws RemoteException {
|
private FingerprintAuthenticationClient createClient(int version) throws RemoteException {
|
||||||
|
return createClient(version, true /* allowBackgroundAuthentication */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FingerprintAuthenticationClient createClient(int version,
|
||||||
|
boolean allowBackgroundAuthentication) throws RemoteException {
|
||||||
when(mHal.getInterfaceVersion()).thenReturn(version);
|
when(mHal.getInterfaceVersion()).thenReturn(version);
|
||||||
|
|
||||||
final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
|
final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
|
||||||
@@ -302,7 +336,11 @@ public class FingerprintAuthenticationClientTest {
|
|||||||
9 /* sensorId */, mBiometricLogger, mBiometricContext,
|
9 /* sensorId */, mBiometricLogger, mBiometricContext,
|
||||||
true /* isStrongBiometric */,
|
true /* isStrongBiometric */,
|
||||||
null /* taskStackListener */, mLockoutCache,
|
null /* taskStackListener */, mLockoutCache,
|
||||||
mUdfpsOverlayController, mSideFpsController,
|
mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication, mSensorProps) {
|
||||||
true /* allowBackgroundAuthentication */, mSensorProps);
|
@Override
|
||||||
|
protected ActivityTaskManager getActivityTaskManager() {
|
||||||
|
return mActivityTaskManager;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user