| /* |
| * 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.systemui.fingerprint; |
| |
| import android.content.Context; |
| import android.content.pm.PackageManager; |
| import android.hardware.biometrics.BiometricPrompt; |
| import android.hardware.biometrics.IBiometricPromptReceiver; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.os.RemoteException; |
| import android.util.Log; |
| import android.view.WindowManager; |
| |
| import com.android.internal.os.SomeArgs; |
| import com.android.systemui.SystemUI; |
| import com.android.systemui.statusbar.CommandQueue; |
| |
| public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Callbacks { |
| private static final String TAG = "FingerprintDialogImpl"; |
| private static final boolean DEBUG = true; |
| |
| protected static final int MSG_SHOW_DIALOG = 1; |
| protected static final int MSG_FINGERPRINT_AUTHENTICATED = 2; |
| protected static final int MSG_FINGERPRINT_HELP = 3; |
| protected static final int MSG_FINGERPRINT_ERROR = 4; |
| protected static final int MSG_HIDE_DIALOG = 5; |
| protected static final int MSG_BUTTON_NEGATIVE = 6; |
| protected static final int MSG_USER_CANCELED = 7; |
| protected static final int MSG_BUTTON_POSITIVE = 8; |
| protected static final int MSG_CLEAR_MESSAGE = 9; |
| |
| |
| private FingerprintDialogView mDialogView; |
| private WindowManager mWindowManager; |
| private IBiometricPromptReceiver mReceiver; |
| private boolean mDialogShowing; |
| |
| private Handler mHandler = new Handler() { |
| @Override |
| public void handleMessage(Message msg) { |
| switch(msg.what) { |
| case MSG_SHOW_DIALOG: |
| handleShowDialog((SomeArgs) msg.obj); |
| break; |
| case MSG_FINGERPRINT_AUTHENTICATED: |
| handleFingerprintAuthenticated(); |
| break; |
| case MSG_FINGERPRINT_HELP: |
| handleFingerprintHelp((String) msg.obj); |
| break; |
| case MSG_FINGERPRINT_ERROR: |
| handleFingerprintError((String) msg.obj); |
| break; |
| case MSG_HIDE_DIALOG: |
| handleHideDialog((Boolean) msg.obj); |
| break; |
| case MSG_BUTTON_NEGATIVE: |
| handleButtonNegative(); |
| break; |
| case MSG_USER_CANCELED: |
| handleUserCanceled(); |
| break; |
| case MSG_BUTTON_POSITIVE: |
| handleButtonPositive(); |
| break; |
| case MSG_CLEAR_MESSAGE: |
| handleClearMessage(); |
| break; |
| } |
| } |
| }; |
| |
| @Override |
| public void start() { |
| if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { |
| return; |
| } |
| getComponent(CommandQueue.class).addCallbacks(this); |
| mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); |
| mDialogView = new FingerprintDialogView(mContext, mHandler); |
| } |
| |
| @Override |
| public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) { |
| if (DEBUG) Log.d(TAG, "showFingerprintDialog"); |
| // Remove these messages as they are part of the previous client |
| mHandler.removeMessages(MSG_FINGERPRINT_ERROR); |
| mHandler.removeMessages(MSG_FINGERPRINT_HELP); |
| mHandler.removeMessages(MSG_FINGERPRINT_AUTHENTICATED); |
| SomeArgs args = SomeArgs.obtain(); |
| args.arg1 = bundle; |
| args.arg2 = receiver; |
| mHandler.obtainMessage(MSG_SHOW_DIALOG, args).sendToTarget(); |
| } |
| |
| @Override |
| public void onFingerprintAuthenticated() { |
| if (DEBUG) Log.d(TAG, "onFingerprintAuthenticated"); |
| mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATED).sendToTarget(); |
| } |
| |
| @Override |
| public void onFingerprintHelp(String message) { |
| if (DEBUG) Log.d(TAG, "onFingerprintHelp: " + message); |
| mHandler.obtainMessage(MSG_FINGERPRINT_HELP, message).sendToTarget(); |
| } |
| |
| @Override |
| public void onFingerprintError(String error) { |
| if (DEBUG) Log.d(TAG, "onFingerprintError: " + error); |
| mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, error).sendToTarget(); |
| } |
| |
| @Override |
| public void hideFingerprintDialog() { |
| if (DEBUG) Log.d(TAG, "hideFingerprintDialog"); |
| mHandler.obtainMessage(MSG_HIDE_DIALOG, false /* userCanceled */).sendToTarget(); |
| } |
| |
| private void handleShowDialog(SomeArgs args) { |
| if (DEBUG) Log.d(TAG, "handleShowDialog, isAnimatingAway: " |
| + mDialogView.isAnimatingAway()); |
| if (mDialogView.isAnimatingAway()) { |
| mDialogView.forceRemove(); |
| } else if (mDialogShowing) { |
| Log.w(TAG, "Dialog already showing"); |
| return; |
| } |
| mReceiver = (IBiometricPromptReceiver) args.arg2; |
| mDialogView.setBundle((Bundle)args.arg1); |
| mWindowManager.addView(mDialogView, mDialogView.getLayoutParams()); |
| mDialogShowing = true; |
| } |
| |
| private void handleFingerprintAuthenticated() { |
| if (DEBUG) Log.d(TAG, "handleFingerprintAuthenticated"); |
| mDialogView.announceForAccessibility( |
| mContext.getResources().getText( |
| com.android.internal.R.string.fingerprint_authenticated)); |
| handleHideDialog(false /* userCanceled */); |
| } |
| |
| private void handleFingerprintHelp(String message) { |
| if (DEBUG) Log.d(TAG, "handleFingerprintHelp: " + message); |
| mDialogView.showHelpMessage(message); |
| } |
| |
| private void handleFingerprintError(String error) { |
| if (DEBUG) Log.d(TAG, "handleFingerprintError: " + error); |
| if (!mDialogShowing) { |
| if (DEBUG) Log.d(TAG, "Dialog already dismissed"); |
| return; |
| } |
| mDialogView.showErrorMessage(error); |
| } |
| |
| private void handleHideDialog(boolean userCanceled) { |
| if (DEBUG) Log.d(TAG, "handleHideDialog, userCanceled: " + userCanceled); |
| if (!mDialogShowing) { |
| // This can happen if there's a race and we get called from both |
| // onAuthenticated and onError, etc. |
| Log.w(TAG, "Dialog already dismissed, userCanceled: " + userCanceled); |
| return; |
| } |
| if (userCanceled) { |
| try { |
| mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); |
| } catch (RemoteException e) { |
| Log.e(TAG, "RemoteException when hiding dialog", e); |
| } |
| } |
| mReceiver = null; |
| mDialogShowing = false; |
| mDialogView.startDismiss(); |
| } |
| |
| private void handleButtonNegative() { |
| if (mReceiver == null) { |
| Log.e(TAG, "Receiver is null"); |
| return; |
| } |
| try { |
| mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE); |
| } catch (RemoteException e) { |
| Log.e(TAG, "Remote exception when handling negative button", e); |
| } |
| handleHideDialog(false /* userCanceled */); |
| } |
| |
| private void handleButtonPositive() { |
| if (mReceiver == null) { |
| Log.e(TAG, "Receiver is null"); |
| return; |
| } |
| try { |
| mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_POSITIVE); |
| } catch (RemoteException e) { |
| Log.e(TAG, "Remote exception when handling positive button", e); |
| } |
| handleHideDialog(false /* userCanceled */); |
| } |
| |
| private void handleClearMessage() { |
| mDialogView.resetMessage(); |
| } |
| |
| private void handleUserCanceled() { |
| handleHideDialog(true /* userCanceled */); |
| } |
| } |