diff options
| author | Kevin Chyn <kchyn@google.com> | 2018-01-18 11:48:09 -0800 |
|---|---|---|
| committer | Kevin Chyn <kchyn@google.com> | 2018-01-23 14:54:48 -0800 |
| commit | aae4a15a2288c20e73b995a590bde4626c887d03 (patch) | |
| tree | cf2a99a37ff46535d753229cc5a1f8295500e290 /core/java | |
| parent | 43137e8e8de3e0ee6aefb9b9e3aa8278eaa8db5b (diff) | |
Add FingerprintDialog API and related plumbing
This commit adds the plumbing which sends the signals from the API
to the component in SysUI. The dialog will be implemented in another
CL in this topic.
Bug: 67497360
Test: Modify Settings to use the new API
Test: FingerprintDialogImpl is able to notify FingerprintDialog clients
of user events
Test: System dialog is dismissed when client application is killed
unexpectedly
Test: Open FP settings, lock device, authenticate, authenticate. Repeat
Change-Id: Id28ec9691646bed765dc069cceb4678d9f6db92e
Diffstat (limited to 'core/java')
6 files changed, 552 insertions, 59 deletions
diff --git a/core/java/android/hardware/fingerprint/FingerprintDialog.java b/core/java/android/hardware/fingerprint/FingerprintDialog.java new file mode 100644 index 000000000000..6b7fab773b43 --- /dev/null +++ b/core/java/android/hardware/fingerprint/FingerprintDialog.java @@ -0,0 +1,293 @@ +/* + * 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 android.hardware.fingerprint; + +import static android.Manifest.permission.USE_FINGERPRINT; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; +import android.content.DialogInterface; +import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; +import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; +import android.hardware.fingerprint.IFingerprintDialogReceiver; +import android.os.Bundle; +import android.os.CancellationSignal; +import android.text.TextUtils; + +import java.util.concurrent.Executor; + +/** + * A class that manages a system-provided fingerprint dialog. + */ +public class FingerprintDialog { + + /** + * @hide + */ + public static final String KEY_TITLE = "title"; + /** + * @hide + */ + public static final String KEY_SUBTITLE = "subtitle"; + /** + * @hide + */ + public static final String KEY_DESCRIPTION = "description"; + /** + * @hide + */ + public static final String KEY_POSITIVE_TEXT = "positive_text"; + /** + * @hide + */ + public static final String KEY_NEGATIVE_TEXT = "negative_text"; + + /** + * Error/help message will show for this amount of time. + * For error messages, the dialog will also be dismissed after this amount of time. + * Error messages will be propagated back to the application via AuthenticationCallback + * after this amount of time. + * @hide + */ + public static final int HIDE_DIALOG_DELAY = 3000; // ms + /** + * @hide + */ + public static final int DISMISSED_REASON_POSITIVE = 1; + + /** + * @hide + */ + public static final int DISMISSED_REASON_NEGATIVE = 2; + + /** + * @hide + */ + public static final int DISMISSED_REASON_USER_CANCEL = 3; + + private static class ButtonInfo { + Executor executor; + DialogInterface.OnClickListener listener; + ButtonInfo(Executor ex, DialogInterface.OnClickListener l) { + executor = ex; + listener = l; + } + } + + /** + * A builder that collects arguments, to be shown on the system-provided fingerprint dialog. + **/ + public static class Builder { + private final Bundle bundle; + private ButtonInfo positiveButtonInfo; + private ButtonInfo negativeButtonInfo; + + /** + * Creates a builder for a fingerprint dialog. + */ + public Builder() { + bundle = new Bundle(); + } + + /** + * Required: Set the title to display. + * @param title + * @return + */ + public Builder setTitle(@NonNull CharSequence title) { + bundle.putCharSequence(KEY_TITLE, title); + return this; + } + + /** + * Optional: Set the subtitle to display. + * @param subtitle + * @return + */ + public Builder setSubtitle(@NonNull CharSequence subtitle) { + bundle.putCharSequence(KEY_SUBTITLE, subtitle); + return this; + } + + /** + * Optional: Set the description to display. + * @param description + * @return + */ + public Builder setDescription(@NonNull CharSequence description) { + bundle.putCharSequence(KEY_DESCRIPTION, description); + return this; + } + + /** + * Optional: Set the text for the positive button. If not set, the positive button + * will not show. + * @param text + * @return + * @hide + */ + public Builder setPositiveButton(@NonNull CharSequence text, + @NonNull @CallbackExecutor Executor executor, + @NonNull DialogInterface.OnClickListener listener) { + if (TextUtils.isEmpty(text)) { + throw new IllegalArgumentException("Text must be set and non-empty"); + } + if (executor == null) { + throw new IllegalArgumentException("Executor must not be null"); + } + if (listener == null) { + throw new IllegalArgumentException("Listener must not be null"); + } + bundle.putCharSequence(KEY_POSITIVE_TEXT, text); + positiveButtonInfo = new ButtonInfo(executor, listener); + return this; + } + + /** + * Required: Set the text for the negative button. + * @param text + * @return + */ + public Builder setNegativeButton(@NonNull CharSequence text, + @NonNull @CallbackExecutor Executor executor, + @NonNull DialogInterface.OnClickListener listener) { + if (TextUtils.isEmpty(text)) { + throw new IllegalArgumentException("Text must be set and non-empty"); + } + if (executor == null) { + throw new IllegalArgumentException("Executor must not be null"); + } + if (listener == null) { + throw new IllegalArgumentException("Listener must not be null"); + } + bundle.putCharSequence(KEY_NEGATIVE_TEXT, text); + negativeButtonInfo = new ButtonInfo(executor, listener); + return this; + } + + /** + * Creates a {@link FingerprintDialog} with the arguments supplied to this builder. + * @param context + * @return a {@link FingerprintDialog} + * @throws IllegalArgumentException if any of the required fields are not set. + */ + public FingerprintDialog build(Context context) { + final CharSequence title = bundle.getCharSequence(KEY_TITLE); + final CharSequence negative = bundle.getCharSequence(KEY_NEGATIVE_TEXT); + + if (TextUtils.isEmpty(title)) { + throw new IllegalArgumentException("Title must be set and non-empty"); + } else if (TextUtils.isEmpty(negative)) { + throw new IllegalArgumentException("Negative text must be set and non-empty"); + } + return new FingerprintDialog(context, bundle, positiveButtonInfo, negativeButtonInfo); + } + } + + private FingerprintManager mFingerprintManager; + private Bundle mBundle; + private ButtonInfo mPositiveButtonInfo; + private ButtonInfo mNegativeButtonInfo; + + IFingerprintDialogReceiver mDialogReceiver = new IFingerprintDialogReceiver.Stub() { + @Override + public void onDialogDismissed(int reason) { + // Check the reason and invoke OnClickListener(s) if necessary + if (reason == DISMISSED_REASON_POSITIVE) { + mPositiveButtonInfo.executor.execute(() -> { + mPositiveButtonInfo.listener.onClick(null, DialogInterface.BUTTON_POSITIVE); + }); + } else if (reason == DISMISSED_REASON_NEGATIVE) { + mNegativeButtonInfo.executor.execute(() -> { + mNegativeButtonInfo.listener.onClick(null, DialogInterface.BUTTON_NEGATIVE); + }); + } + } + }; + + private FingerprintDialog(Context context, Bundle bundle, + ButtonInfo positiveButtonInfo, ButtonInfo negativeButtonInfo) { + mBundle = bundle; + mPositiveButtonInfo = positiveButtonInfo; + mNegativeButtonInfo = negativeButtonInfo; + mFingerprintManager = context.getSystemService(FingerprintManager.class); + } + + /** + * This call warms up the fingerprint hardware, displays a system-provided dialog, + * and starts scanning for a fingerprint. It terminates when + * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when + * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, + * when {@link AuthenticationCallback#onAuthenticationFailed()} is called or when the user + * dismisses the system-provided dialog, at which point the crypto object becomes invalid. + * This operation can be canceled by using the provided cancel object. The application will + * receive authentication errors through {@link AuthenticationCallback}, and button events + * through the corresponding callback set in + * {@link Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}. + * It is safe to reuse the {@link FingerprintDialog} object, and calling + * {@link FingerprintDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)} + * while an existing authentication attempt is occurring will stop the previous client and + * start a new authentication. The interrupted client will receive a cancelled notification + * through {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}. + * + * @throws IllegalArgumentException if any of the arguments are null + * + * @param crypto object associated with the call + * @param cancel an object that can be used to cancel authentication + * @param executor an executor to handle callback events + * @param callback an object to receive authentication events + */ + @RequiresPermission(USE_FINGERPRINT) + public void authenticate(@NonNull FingerprintManager.CryptoObject crypto, + @NonNull CancellationSignal cancel, + @NonNull @CallbackExecutor Executor executor, + @NonNull FingerprintManager.AuthenticationCallback callback) { + mFingerprintManager.authenticate(crypto, cancel, mBundle, executor, mDialogReceiver, + callback); + } + + /** + * This call warms up the fingerprint hardware, displays a system-provided dialog, + * and starts scanning for a fingerprint. It terminates when + * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when + * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, + * when {@link AuthenticationCallback#onAuthenticationFailed()} is called or when the user + * dismisses the system-provided dialog. This operation can be canceled by using the provided + * cancel object. The application will receive authentication errors through + * {@link AuthenticationCallback}, and button events through the corresponding callback set in + * {@link Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}. + * It is safe to reuse the {@link FingerprintDialog} object, and calling + * {@link FingerprintDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)} + * while an existing authentication attempt is occurring will stop the previous client and + * start a new authentication. The interrupted client will receive a cancelled notification + * through {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}. + * + * @throws IllegalArgumentException if any of the arguments are null + * + * @param cancel an object that can be used to cancel authentication + * @param executor an executor to handle callback events + * @param callback an object to receive authentication events + */ + @RequiresPermission(USE_FINGERPRINT) + public void authenticate(@NonNull CancellationSignal cancel, + @NonNull @CallbackExecutor Executor executor, + @NonNull FingerprintManager.AuthenticationCallback callback) { + mFingerprintManager.authenticate(cancel, mBundle, executor, mDialogReceiver, callback); + } +} diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 987718a82c47..1a0b276776c3 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -16,6 +16,11 @@ package android.hardware.fingerprint; +import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.Manifest.permission.MANAGE_FINGERPRINT; +import static android.Manifest.permission.USE_FINGERPRINT; + +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -23,6 +28,7 @@ import android.annotation.SystemService; import android.app.ActivityManager; import android.content.Context; import android.os.Binder; +import android.os.Bundle; import android.os.CancellationSignal; import android.os.CancellationSignal.OnCancelListener; import android.os.Handler; @@ -38,14 +44,11 @@ import android.util.Slog; import java.security.Signature; import java.util.List; +import java.util.concurrent.Executor; import javax.crypto.Cipher; import javax.crypto.Mac; -import static android.Manifest.permission.INTERACT_ACROSS_USERS; -import static android.Manifest.permission.MANAGE_FINGERPRINT; -import static android.Manifest.permission.USE_FINGERPRINT; - /** * A class that coordinates access to the fingerprint hardware. */ @@ -204,6 +207,7 @@ public class FingerprintManager { private CryptoObject mCryptoObject; private Fingerprint mRemovalFingerprint; private Handler mHandler; + private Executor mExecutor; private class OnEnrollCancelListener implements OnCancelListener { @Override @@ -505,7 +509,9 @@ public class FingerprintManager { } /** - * Per-user version + * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject, + * CancellationSignal, int, AuthenticationCallback, Handler)} + * @param userId the user ID that the fingerprint hardware will authenticate for. * @hide */ @RequiresPermission(USE_FINGERPRINT) @@ -530,7 +536,7 @@ public class FingerprintManager { mCryptoObject = crypto; long sessionId = crypto != null ? crypto.getOpId() : 0; mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags, - mContext.getOpPackageName()); + mContext.getOpPackageName(), null /* bundle */, null /* receiver */); } catch (RemoteException e) { Log.w(TAG, "Remote exception while authenticating: ", e); if (callback != null) { @@ -543,6 +549,112 @@ public class FingerprintManager { } /** + * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject, + * CancellationSignal, Bundle, Executor, IFingerprintDialogReceiver, AuthenticationCallback)} + * @param userId the user ID that the fingerprint hardware will authenticate for. + * @hide + */ + public void authenticate(int userId, + @Nullable CryptoObject crypto, + @NonNull CancellationSignal cancel, + @NonNull Bundle bundle, + @NonNull @CallbackExecutor Executor executor, + @NonNull IFingerprintDialogReceiver receiver, + @NonNull AuthenticationCallback callback) { + mCryptoObject = crypto; + if (cancel.isCanceled()) { + Log.w(TAG, "authentication already canceled"); + return; + } else { + cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); + } + + if (mService != null) { + try { + mExecutor = executor; + mAuthenticationCallback = callback; + final long sessionId = crypto != null ? crypto.getOpId() : 0; + mService.authenticate(mToken, sessionId, userId, mServiceReceiver, + 0 /* flags */, mContext.getOpPackageName(), bundle, receiver); + } catch (RemoteException e) { + Log.w(TAG, "Remote exception while authenticating", e); + mExecutor.execute(() -> { + callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE, + getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */)); + }); + } + } + } + + /** + * Private method, see {@link FingerprintDialog#authenticate(CancellationSignal, Executor, + * AuthenticationCallback)} + * @param cancel + * @param executor + * @param callback + * @hide + */ + public void authenticate( + @NonNull CancellationSignal cancel, + @NonNull Bundle bundle, + @NonNull @CallbackExecutor Executor executor, + @NonNull IFingerprintDialogReceiver receiver, + @NonNull AuthenticationCallback callback) { + if (cancel == null) { + throw new IllegalArgumentException("Must supply a cancellation signal"); + } + if (bundle == null) { + throw new IllegalArgumentException("Must supply a bundle"); + } + if (executor == null) { + throw new IllegalArgumentException("Must supply an executor"); + } + if (receiver == null) { + throw new IllegalArgumentException("Must supply a receiver"); + } + if (callback == null) { + throw new IllegalArgumentException("Must supply a calback"); + } + authenticate(UserHandle.myUserId(), null, cancel, bundle, executor, receiver, callback); + } + + /** + * Private method, see {@link FingerprintDialog#authenticate(CryptoObject, CancellationSignal, + * Executor, AuthenticationCallback)} + * @param crypto + * @param cancel + * @param executor + * @param callback + * @hide + */ + public void authenticate(@NonNull CryptoObject crypto, + @NonNull CancellationSignal cancel, + @NonNull Bundle bundle, + @NonNull @CallbackExecutor Executor executor, + @NonNull IFingerprintDialogReceiver receiver, + @NonNull AuthenticationCallback callback) { + if (crypto == null) { + throw new IllegalArgumentException("Must supply a crypto object"); + } + if (cancel == null) { + throw new IllegalArgumentException("Must supply a cancellation signal"); + } + if (bundle == null) { + throw new IllegalArgumentException("Must supply a bundle"); + } + if (executor == null) { + throw new IllegalArgumentException("Must supply an executor"); + } + if (receiver == null) { + throw new IllegalArgumentException("Must supply a receiver"); + } + if (callback == null) { + throw new IllegalArgumentException("Must supply a calback"); + } + authenticate(UserHandle.myUserId(), crypto, cancel, bundle, executor, receiver, callback); + } + + /** * Request fingerprint enrollment. This call warms up the fingerprint hardware * and starts scanning for fingerprints. Progress will be indicated by callbacks to the * {@link EnrollmentCallback} object. It terminates when @@ -929,63 +1041,63 @@ public class FingerprintManager { } } - private void sendErrorResult(long deviceId, int errMsgId, int vendorCode) { - // emulate HAL 2.1 behavior and send real errMsgId - final int clientErrMsgId = errMsgId == FINGERPRINT_ERROR_VENDOR - ? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId; - if (mEnrollmentCallback != null) { - mEnrollmentCallback.onEnrollmentError(clientErrMsgId, - getErrorString(errMsgId, vendorCode)); - } else if (mAuthenticationCallback != null) { - mAuthenticationCallback.onAuthenticationError(clientErrMsgId, - getErrorString(errMsgId, vendorCode)); - } else if (mRemovalCallback != null) { - mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId, - getErrorString(errMsgId, vendorCode)); - } else if (mEnumerateCallback != null) { - mEnumerateCallback.onEnumerateError(clientErrMsgId, - getErrorString(errMsgId, vendorCode)); - } - } - private void sendEnrollResult(Fingerprint fp, int remaining) { if (mEnrollmentCallback != null) { mEnrollmentCallback.onEnrollmentProgress(remaining); } } + }; - private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) { - if (mAuthenticationCallback != null) { - final AuthenticationResult result = - new AuthenticationResult(mCryptoObject, fp, userId); - mAuthenticationCallback.onAuthenticationSucceeded(result); - } + private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) { + if (mAuthenticationCallback != null) { + final AuthenticationResult result = + new AuthenticationResult(mCryptoObject, fp, userId); + mAuthenticationCallback.onAuthenticationSucceeded(result); } + } - private void sendAuthenticatedFailed() { - if (mAuthenticationCallback != null) { - mAuthenticationCallback.onAuthenticationFailed(); - } + private void sendAuthenticatedFailed() { + if (mAuthenticationCallback != null) { + mAuthenticationCallback.onAuthenticationFailed(); } + } - private void sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode) { - if (mAuthenticationCallback != null) { - mAuthenticationCallback.onAuthenticationAcquired(acquireInfo); - } - final String msg = getAcquiredString(acquireInfo, vendorCode); - if (msg == null) { - return; - } - // emulate HAL 2.1 behavior and send real acquiredInfo - final int clientInfo = acquireInfo == FINGERPRINT_ACQUIRED_VENDOR - ? (vendorCode + FINGERPRINT_ACQUIRED_VENDOR_BASE) : acquireInfo; - if (mEnrollmentCallback != null) { - mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg); - } else if (mAuthenticationCallback != null) { - mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg); - } + private void sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode) { + if (mAuthenticationCallback != null) { + mAuthenticationCallback.onAuthenticationAcquired(acquireInfo); } - }; + final String msg = getAcquiredString(acquireInfo, vendorCode); + if (msg == null) { + return; + } + // emulate HAL 2.1 behavior and send real acquiredInfo + final int clientInfo = acquireInfo == FINGERPRINT_ACQUIRED_VENDOR + ? (vendorCode + FINGERPRINT_ACQUIRED_VENDOR_BASE) : acquireInfo; + if (mEnrollmentCallback != null) { + mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg); + } else if (mAuthenticationCallback != null) { + mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg); + } + } + + private void sendErrorResult(long deviceId, int errMsgId, int vendorCode) { + // emulate HAL 2.1 behavior and send real errMsgId + final int clientErrMsgId = errMsgId == FINGERPRINT_ERROR_VENDOR + ? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId; + if (mEnrollmentCallback != null) { + mEnrollmentCallback.onEnrollmentError(clientErrMsgId, + getErrorString(errMsgId, vendorCode)); + } else if (mAuthenticationCallback != null) { + mAuthenticationCallback.onAuthenticationError(clientErrMsgId, + getErrorString(errMsgId, vendorCode)); + } else if (mRemovalCallback != null) { + mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId, + getErrorString(errMsgId, vendorCode)); + } else if (mEnumerateCallback != null) { + mEnumerateCallback.onEnumerateError(clientErrMsgId, + getErrorString(errMsgId, vendorCode)); + } + } /** * @hide @@ -1023,7 +1135,10 @@ public class FingerprintManager { } } - private String getErrorString(int errMsg, int vendorCode) { + /** + * @hide + */ + public String getErrorString(int errMsg, int vendorCode) { switch (errMsg) { case FINGERPRINT_ERROR_UNABLE_TO_PROCESS: return mContext.getString( @@ -1043,6 +1158,9 @@ public class FingerprintManager { case FINGERPRINT_ERROR_LOCKOUT_PERMANENT: return mContext.getString( com.android.internal.R.string.fingerprint_error_lockout_permanent); + case FINGERPRINT_ERROR_USER_CANCELED: + return mContext.getString( + com.android.internal.R.string.fingerprint_error_user_canceled); case FINGERPRINT_ERROR_VENDOR: { String[] msgArray = mContext.getResources().getStringArray( com.android.internal.R.array.fingerprint_error_vendor); @@ -1055,7 +1173,10 @@ public class FingerprintManager { return null; } - private String getAcquiredString(int acquireInfo, int vendorCode) { + /** + * @hide + */ + public String getAcquiredString(int acquireInfo, int vendorCode) { switch (acquireInfo) { case FINGERPRINT_ACQUIRED_GOOD: return null; @@ -1096,22 +1217,47 @@ public class FingerprintManager { @Override // binder call public void onAcquired(long deviceId, int acquireInfo, int vendorCode) { - mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode, deviceId).sendToTarget(); + if (mExecutor != null) { + mExecutor.execute(() -> { + sendAcquiredResult(deviceId, acquireInfo, vendorCode); + }); + } else { + mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode, + deviceId).sendToTarget(); + } } @Override // binder call public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) { - mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget(); + if (mExecutor != null) { + mExecutor.execute(() -> { + sendAuthenticatedSucceeded(fp, userId); + }); + } else { + mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget(); + } } @Override // binder call public void onAuthenticationFailed(long deviceId) { - mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget(); + if (mExecutor != null) { + mExecutor.execute(() -> { + sendAuthenticatedFailed(); + }); + } else { + mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget(); + } } @Override // binder call public void onError(long deviceId, int error, int vendorCode) { - mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget(); + if (mExecutor != null) { + mExecutor.execute(() -> { + sendErrorResult(deviceId, error, vendorCode); + }); + } else { + mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget(); + } } @Override // binder call diff --git a/core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl new file mode 100644 index 000000000000..13e79741e543 --- /dev/null +++ b/core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl @@ -0,0 +1,28 @@ +/* + * 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 android.hardware.fingerprint; + +import android.hardware.fingerprint.Fingerprint; +import android.os.Bundle; +import android.os.UserHandle; + +/** + * Communication channel from the FingerprintDialog (SysUI) back to AuthenticationClient. + * @hide + */ +oneway interface IFingerprintDialogReceiver { + void onDialogDismissed(int reason); +} diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 4879d54768fb..f1502e489c11 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -17,6 +17,7 @@ package android.hardware.fingerprint; import android.os.Bundle; import android.hardware.fingerprint.IFingerprintClientActiveCallback; +import android.hardware.fingerprint.IFingerprintDialogReceiver; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback; import android.hardware.fingerprint.Fingerprint; @@ -29,7 +30,8 @@ import java.util.List; interface IFingerprintService { // Authenticate the given sessionId with a fingerprint void authenticate(IBinder token, long sessionId, int userId, - IFingerprintServiceReceiver receiver, int flags, String opPackageName); + IFingerprintServiceReceiver receiver, int flags, String opPackageName, + in Bundle bundle, IFingerprintDialogReceiver dialogReceiver); // Cancel authentication for the given sessionId void cancelAuthentication(IBinder token, String opPackageName); diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index e097362a3fe8..f5af80a29ed1 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -18,6 +18,7 @@ package com.android.internal.statusbar; import android.content.ComponentName; import android.graphics.Rect; +import android.hardware.fingerprint.IFingerprintDialogReceiver; import android.os.Bundle; import android.service.notification.StatusBarNotification; @@ -130,4 +131,15 @@ oneway interface IStatusBar void handleSystemKey(in int key); void showShutdownUi(boolean isReboot, String reason); + + // Used to show the dialog when FingerprintService starts authentication + void showFingerprintDialog(in Bundle bundle, IFingerprintDialogReceiver receiver); + // Used to hide the dialog when a finger is authenticated + void onFingerprintAuthenticated(); + // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc + void onFingerprintHelp(String message); + // Used to set a message - the dialog will dismiss after a certain amount of time + void onFingerprintError(String error); + // Used to hide the fingerprint dialog when the authenticationclient is stopped + void hideFingerprintDialog(); } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 03603e401110..cb0b53c495dc 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.graphics.Rect; import android.os.Bundle; import android.service.notification.StatusBarNotification; +import android.hardware.fingerprint.IFingerprintDialogReceiver; import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.StatusBarIcon; @@ -79,4 +80,15 @@ interface IStatusBarService void remTile(in ComponentName tile); void clickTile(in ComponentName tile); void handleSystemKey(in int key); + + // Used to show the dialog when FingerprintService starts authentication + void showFingerprintDialog(in Bundle bundle, IFingerprintDialogReceiver receiver); + // Used to hide the dialog when a finger is authenticated + void onFingerprintAuthenticated(); + // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc + void onFingerprintHelp(String message); + // Used to set a message - the dialog will dismiss after a certain amount of time + void onFingerprintError(String error); + // Used to hide the fingerprint dialog when the authenticationclient is stopped + void hideFingerprintDialog(); } |
