• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.biometrics;
18 
19 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
20 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
21 import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
22 import static android.view.Display.INVALID_DISPLAY;
23 
24 import static com.android.systemui.Flags.contAuthPlugin;
25 
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.app.ActivityTaskManager;
29 import android.app.KeyguardManager;
30 import android.app.TaskStackListener;
31 import android.content.BroadcastReceiver;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.IntentFilter;
35 import android.content.res.Configuration;
36 import android.content.res.Resources;
37 import android.graphics.Point;
38 import android.graphics.Rect;
39 import android.hardware.SensorPrivacyManager;
40 import android.hardware.biometrics.BiometricAuthenticator.Modality;
41 import android.hardware.biometrics.BiometricConstants;
42 import android.hardware.biometrics.BiometricManager.Authenticators;
43 import android.hardware.biometrics.BiometricPrompt;
44 import android.hardware.biometrics.BiometricStateListener;
45 import android.hardware.biometrics.IBiometricContextListener;
46 import android.hardware.biometrics.IBiometricSysuiReceiver;
47 import android.hardware.biometrics.PromptInfo;
48 import android.hardware.display.DisplayManager;
49 import android.hardware.face.FaceManager;
50 import android.hardware.face.FaceSensorPropertiesInternal;
51 import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
52 import android.hardware.fingerprint.FingerprintManager;
53 import android.hardware.fingerprint.FingerprintSensorProperties;
54 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
55 import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
56 import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
57 import android.os.Handler;
58 import android.os.RemoteException;
59 import android.os.UserHandle;
60 import android.os.UserManager;
61 import android.util.Log;
62 import android.util.RotationUtils;
63 import android.util.SparseBooleanArray;
64 import android.view.Display;
65 import android.view.DisplayInfo;
66 import android.view.MotionEvent;
67 import android.view.WindowManager;
68 
69 import com.android.internal.R;
70 import com.android.internal.annotations.VisibleForTesting;
71 import com.android.internal.jank.InteractionJankMonitor;
72 import com.android.internal.os.SomeArgs;
73 import com.android.internal.widget.LockPatternUtils;
74 import com.android.systemui.CoreStartable;
75 import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
76 import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
77 import com.android.systemui.biometrics.plugins.AuthContextPlugins;
78 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
79 import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
80 import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
81 import com.android.systemui.dagger.SysUISingleton;
82 import com.android.systemui.dagger.qualifiers.Application;
83 import com.android.systemui.dagger.qualifiers.Background;
84 import com.android.systemui.dagger.qualifiers.Main;
85 import com.android.systemui.doze.DozeReceiver;
86 import com.android.systemui.keyguard.WakefulnessLifecycle;
87 import com.android.systemui.keyguard.data.repository.BiometricType;
88 import com.android.systemui.log.core.LogLevel;
89 import com.android.systemui.statusbar.CommandQueue;
90 import com.android.systemui.statusbar.VibratorHelper;
91 import com.android.systemui.statusbar.policy.ConfigurationController;
92 import com.android.systemui.util.concurrency.DelayableExecutor;
93 import com.android.systemui.util.concurrency.Execution;
94 import com.android.systemui.utils.windowmanager.WindowManagerProvider;
95 
96 import com.google.android.msdl.domain.MSDLPlayer;
97 
98 import dagger.Lazy;
99 
100 import kotlin.Unit;
101 
102 import kotlinx.coroutines.CoroutineScope;
103 import kotlinx.coroutines.Job;
104 
105 import java.io.PrintWriter;
106 import java.util.ArrayList;
107 import java.util.Arrays;
108 import java.util.HashMap;
109 import java.util.HashSet;
110 import java.util.List;
111 import java.util.Map;
112 import java.util.Objects;
113 import java.util.Optional;
114 import java.util.Set;
115 
116 import javax.inject.Inject;
117 import javax.inject.Provider;
118 
119 /**
120  * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
121  * appropriate biometric UI (e.g. BiometricDialogView).
122  *
123  * Also coordinates biometric-related things, such as UDFPS, with
124  * {@link com.android.keyguard.KeyguardUpdateMonitor}
125  */
126 @SysUISingleton
127 public class AuthController implements
128         CoreStartable,
129         ConfigurationController.ConfigurationListener,
130         CommandQueue.Callbacks,
131         AuthDialogCallback,
132         DozeReceiver {
133 
134     private static final String TAG = "AuthController";
135     private static final boolean DEBUG = true;
136     private static final int SENSOR_PRIVACY_DELAY = 500;
137 
138     private final Handler mHandler;
139     private final Context mContext;
140     private final Execution mExecution;
141     private final CommandQueue mCommandQueue;
142     private final ActivityTaskManager mActivityTaskManager;
143     @Nullable private final FingerprintManager mFingerprintManager;
144     @Nullable private final FaceManager mFaceManager;
145     @Nullable private final AuthContextPlugins mContextPlugins;
146     private final Provider<UdfpsController> mUdfpsControllerFactory;
147     private final CoroutineScope mApplicationCoroutineScope;
148     private Job mBiometricContextListenerJob = null;
149 
150     // TODO: these should be migrated out once ready
151     @NonNull private final Provider<PromptSelectorInteractor> mPromptSelectorInteractor;
152     @NonNull private final Provider<CredentialViewModel> mCredentialViewModelProvider;
153     @NonNull private final Provider<PromptViewModel> mPromptViewModelProvider;
154     @NonNull private final Lazy<LogContextInteractor> mLogContextInteractor;
155 
156     private final Display mDisplay;
157     private float mScaleFactor = 1f;
158     @Nullable private Point mFingerprintSensorLocation;
159     @Nullable private Rect mUdfpsBounds;
160     private final Set<Callback> mCallbacks = new HashSet<>();
161 
162     // TODO: These should just be saved from onSaveState
163     private SomeArgs mCurrentDialogArgs;
164     @VisibleForTesting
165     AuthContainerView mCurrentDialog;
166 
167     @NonNull private final WindowManager mWindowManager;
168     @NonNull private final DisplayManager mDisplayManager;
169     @Nullable private UdfpsController mUdfpsController;
170     @Nullable private UdfpsOverlayParams mUdfpsOverlayParams;
171     @Nullable private IUdfpsRefreshRateRequestCallback mUdfpsRefreshRateRequestCallback;
172     @NonNull private Lazy<UdfpsLogger> mUdfpsLogger;
173     @VisibleForTesting IBiometricSysuiReceiver mReceiver;
174     @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener;
175     @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
176     @Nullable private List<FingerprintSensorPropertiesInternal> mFpProps;
177     @Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
178     @Nullable private List<FingerprintSensorPropertiesInternal> mSidefpsProps;
179 
180     @NonNull private final Map<Integer, Boolean> mFpEnrolledForUser = new HashMap<>();
181     @NonNull private final SparseBooleanArray mUdfpsEnrolledForUser;
182     @NonNull private final SparseBooleanArray mFaceEnrolledForUser;
183     @NonNull private final SparseBooleanArray mSfpsEnrolledForUser;
184     @NonNull private final SensorPrivacyManager mSensorPrivacyManager;
185     private final WakefulnessLifecycle mWakefulnessLifecycle;
186     private boolean mAllFingerprintAuthenticatorsRegistered;
187     @NonNull private final UserManager mUserManager;
188     @NonNull private final LockPatternUtils mLockPatternUtils;
189     @NonNull private final InteractionJankMonitor mInteractionJankMonitor;
190     @NonNull private final UdfpsUtils mUdfpsUtils;
191     private final @Background DelayableExecutor mBackgroundExecutor;
192     private final DisplayInfo mCachedDisplayInfo = new DisplayInfo();
193     @NonNull private final VibratorHelper mVibratorHelper;
194     @NonNull private final MSDLPlayer mMSDLPlayer;
195 
196     private final WindowManagerProvider mWindowManagerProvider;
197 
198     @VisibleForTesting
199     final TaskStackListener mTaskStackListener = new TaskStackListener() {
200         @Override
201         public void onTaskStackChanged() {
202             if (isOwnerInBackground()) {
203                 mHandler.post(AuthController.this::cancelIfOwnerIsNotInForeground);
204             }
205         }
206     };
207 
208     @VisibleForTesting
209     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
210         @Override
211         public void onReceive(Context context, Intent intent) {
212             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
213                 String reason = intent.getStringExtra("reason");
214                 reason = (reason != null) ? reason : "unknown";
215                 closeDialog(reason);
216             }
217         }
218     };
219 
closeDialog(String reasonString)220     private void closeDialog(String reasonString) {
221         closeDialog(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, reasonString);
222     }
223 
closeDialog(@iometricPrompt.DismissedReason int reason, String reasonString)224     private void closeDialog(@BiometricPrompt.DismissedReason int reason, String reasonString) {
225         if (isShowing()) {
226             Log.i(TAG, "Close BP, reason :" + reasonString);
227             mCurrentDialog.dismissWithoutCallback(true /* animate */);
228             mCurrentDialog = null;
229 
230             for (Callback cb : mCallbacks) {
231                 cb.onBiometricPromptDismissed();
232             }
233 
234             try {
235                 if (mReceiver != null) {
236                     mReceiver.onDialogDismissed(reason, null /* credentialAttestation */);
237                     mReceiver = null;
238                 }
239             } catch (RemoteException e) {
240                 Log.e(TAG, "Remote exception", e);
241             }
242         }
243     }
244 
isOwnerInBackground()245     private boolean isOwnerInBackground() {
246         if (mCurrentDialog != null) {
247             final String clientPackage = mCurrentDialog.getOpPackageName();
248             final String clientClassNameIfItIsConfirmDeviceCredentialActivity =
249                     mCurrentDialog.getClassNameIfItIsConfirmDeviceCredentialActivity();
250             final boolean isInBackground = Utils.isSystemAppOrInBackground(mActivityTaskManager,
251                     mContext, clientPackage,
252                     clientClassNameIfItIsConfirmDeviceCredentialActivity);
253             if (isInBackground) {
254                 Log.w(TAG, "Evicting client due to top activity is not : " + clientPackage);
255             }
256             return isInBackground;
257         }
258         return false;
259     }
260 
cancelIfOwnerIsNotInForeground()261     private void cancelIfOwnerIsNotInForeground() {
262         mExecution.assertIsMainThread();
263         closeDialog("owner not in foreground");
264     }
265 
266     /**
267      * Whether all fingerprint authentictors have been registered.
268      */
areAllFingerprintAuthenticatorsRegistered()269     public boolean areAllFingerprintAuthenticatorsRegistered() {
270         return mAllFingerprintAuthenticatorsRegistered;
271     }
272 
handleAllFingerprintAuthenticatorsRegistered( List<FingerprintSensorPropertiesInternal> sensors)273     private void handleAllFingerprintAuthenticatorsRegistered(
274             List<FingerprintSensorPropertiesInternal> sensors) {
275         mExecution.assertIsMainThread();
276         if (DEBUG) {
277             Log.d(TAG, "handleAllFingerprintAuthenticatorsRegistered | sensors: "
278                     + Arrays.toString(sensors.toArray()));
279         }
280         mAllFingerprintAuthenticatorsRegistered = true;
281         mFpProps = sensors;
282 
283         List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>();
284         List<FingerprintSensorPropertiesInternal> sidefpsProps = new ArrayList<>();
285         for (FingerprintSensorPropertiesInternal props : mFpProps) {
286             if (props.isAnyUdfpsType()) {
287                 udfpsProps.add(props);
288             }
289             if (props.isAnySidefpsType()) {
290                 sidefpsProps.add(props);
291             }
292         }
293 
294         mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null;
295         if (mUdfpsProps != null) {
296             mUdfpsController = mUdfpsControllerFactory.get();
297             mUdfpsController.addCallback(new UdfpsController.Callback() {
298                 @Override
299                 public void onFingerUp() {
300                 }
301 
302                 @Override
303                 public void onFingerDown() {
304                     if (mCurrentDialog != null) {
305                         mCurrentDialog.onPointerDown();
306                     }
307                 }
308             });
309             mUdfpsController.setAuthControllerUpdateUdfpsLocation(this::updateUdfpsLocation);
310             mUdfpsController.setUdfpsDisplayMode(new UdfpsDisplayMode(mContext, mExecution,
311                     this, mUdfpsLogger.get()));
312             mUdfpsBounds = mUdfpsProps.get(0).getLocation().getRect();
313         }
314         mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null;
315         mFingerprintManager.registerBiometricStateListener(new BiometricStateListener() {
316             @Override
317             public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
318                 mHandler.post(() -> handleEnrollmentsChanged(
319                         TYPE_FINGERPRINT, userId, sensorId, hasEnrollments));
320             }
321         });
322         updateSensorLocations();
323 
324         for (Callback cb : mCallbacks) {
325             cb.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT);
326         }
327     }
328 
handleAllFaceAuthenticatorsRegistered(List<FaceSensorPropertiesInternal> sensors)329     private void handleAllFaceAuthenticatorsRegistered(List<FaceSensorPropertiesInternal> sensors) {
330         mExecution.assertIsMainThread();
331         if (DEBUG) {
332             Log.d(TAG, "handleAllFaceAuthenticatorsRegistered | sensors: " + Arrays.toString(
333                     sensors.toArray()));
334         }
335 
336         mFaceManager.registerBiometricStateListener(new BiometricStateListener() {
337             @Override
338             public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
339                 mHandler.post(() -> handleEnrollmentsChanged(
340                         TYPE_FACE, userId, sensorId, hasEnrollments));
341             }
342         });
343 
344         for (Callback cb : mCallbacks) {
345             cb.onAllAuthenticatorsRegistered(TYPE_FACE);
346         }
347     }
348 
handleEnrollmentsChanged(@odality int modality, int userId, int sensorId, boolean hasEnrollments)349     private void handleEnrollmentsChanged(@Modality int modality, int userId, int sensorId,
350             boolean hasEnrollments) {
351         mExecution.assertIsMainThread();
352         Log.d(TAG, "handleEnrollmentsChanged, userId: " + userId + ", sensorId: " + sensorId
353                 + ", hasEnrollments: " + hasEnrollments);
354         BiometricType sensorBiometricType = BiometricType.UNKNOWN;
355         if (mFpProps != null) {
356             for (FingerprintSensorPropertiesInternal prop: mFpProps) {
357                 if (prop.sensorId == sensorId) {
358                     mFpEnrolledForUser.put(userId, hasEnrollments);
359                     if (prop.isAnyUdfpsType()) {
360                         sensorBiometricType = BiometricType.UNDER_DISPLAY_FINGERPRINT;
361                         mUdfpsEnrolledForUser.put(userId, hasEnrollments);
362                     } else if (prop.isAnySidefpsType()) {
363                         sensorBiometricType = BiometricType.SIDE_FINGERPRINT;
364                         mSfpsEnrolledForUser.put(userId, hasEnrollments);
365                     } else if (prop.sensorType == TYPE_REAR) {
366                         sensorBiometricType = BiometricType.REAR_FINGERPRINT;
367                     }
368                     break;
369                 }
370             }
371         }
372         if (mFaceProps == null) {
373             Log.d(TAG, "handleEnrollmentsChanged, mFaceProps is null");
374         } else {
375             for (FaceSensorPropertiesInternal prop : mFaceProps) {
376                 if (prop.sensorId == sensorId) {
377                     mFaceEnrolledForUser.put(userId, hasEnrollments);
378                     sensorBiometricType = BiometricType.FACE;
379                     break;
380                 }
381             }
382         }
383         for (Callback cb : mCallbacks) {
384             cb.onEnrollmentsChanged(modality);
385             cb.onEnrollmentsChanged(sensorBiometricType, userId, hasEnrollments);
386         }
387     }
388 
389     /**
390      * Adds a callback. See {@link Callback}.
391      */
addCallback(@onNull Callback callback)392     public void addCallback(@NonNull Callback callback) {
393         mCallbacks.add(callback);
394     }
395 
396     /**
397      * Removes a callback. See {@link Callback}.
398      */
removeCallback(@onNull Callback callback)399     public void removeCallback(@NonNull Callback callback) {
400         mCallbacks.remove(callback);
401     }
402 
403     @Override
dozeTimeTick()404     public void dozeTimeTick() {
405         if (mUdfpsController != null) {
406             mUdfpsController.dozeTimeTick();
407         }
408     }
409 
410     @Override
onTryAgainPressed(long requestId)411     public void onTryAgainPressed(long requestId) {
412         final IBiometricSysuiReceiver receiver = getCurrentReceiver(requestId);
413         if (receiver == null) {
414             Log.w(TAG, "Skip onTryAgainPressed");
415             return;
416         }
417 
418         try {
419             receiver.onTryAgainPressed();
420         } catch (RemoteException e) {
421             Log.e(TAG, "RemoteException when handling try again", e);
422         }
423     }
424 
425     @Override
onDeviceCredentialPressed(long requestId)426     public void onDeviceCredentialPressed(long requestId) {
427         final IBiometricSysuiReceiver receiver = getCurrentReceiver(requestId);
428         if (receiver == null) {
429             Log.w(TAG, "Skip onDeviceCredentialPressed");
430             return;
431         }
432 
433         try {
434             receiver.onDeviceCredentialPressed();
435         } catch (RemoteException e) {
436             Log.e(TAG, "RemoteException when handling credential button", e);
437         }
438     }
439 
440     @Override
onSystemEvent(int event, long requestId)441     public void onSystemEvent(int event, long requestId) {
442         final IBiometricSysuiReceiver receiver = getCurrentReceiver(requestId);
443         if (receiver == null) {
444             Log.w(TAG, "Skip onSystemEvent");
445             return;
446         }
447 
448         try {
449             receiver.onSystemEvent(event);
450         } catch (RemoteException e) {
451             Log.e(TAG, "RemoteException when sending system event", e);
452         }
453     }
454 
455     @Override
onDialogAnimatedIn(long requestId, boolean startFingerprintNow)456     public void onDialogAnimatedIn(long requestId, boolean startFingerprintNow) {
457         final IBiometricSysuiReceiver receiver = getCurrentReceiver(requestId);
458         if (receiver == null) {
459             Log.w(TAG, "Skip onDialogAnimatedIn");
460             return;
461         }
462 
463         try {
464             receiver.onDialogAnimatedIn(startFingerprintNow);
465         } catch (RemoteException e) {
466             Log.e(TAG, "RemoteException when sending onDialogAnimatedIn", e);
467         }
468     }
469 
470     @Override
onStartFingerprintNow(long requestId)471     public void onStartFingerprintNow(long requestId) {
472         final IBiometricSysuiReceiver receiver = getCurrentReceiver(requestId);
473         if (receiver == null) {
474             Log.e(TAG, "onStartUdfpsNow: Receiver is null");
475             return;
476         }
477 
478         try {
479             receiver.onStartFingerprintNow();
480         } catch (RemoteException e) {
481             Log.e(TAG, "RemoteException when sending onDialogAnimatedIn", e);
482         }
483     }
484 
485     @Nullable
getCurrentReceiver(long requestId)486     private IBiometricSysuiReceiver getCurrentReceiver(long requestId) {
487         if (!isRequestIdValid(requestId)) {
488             return null;
489         }
490 
491         if (mReceiver == null) {
492             Log.w(TAG, "getCurrentReceiver: Receiver is null");
493         }
494 
495         return mReceiver;
496     }
497 
isRequestIdValid(long requestId)498     private boolean isRequestIdValid(long requestId) {
499         if (mCurrentDialog == null) {
500             Log.w(TAG, "shouldNotifyReceiver: dialog already gone");
501             return false;
502         }
503 
504         if (requestId != mCurrentDialog.getRequestId()) {
505             Log.w(TAG, "shouldNotifyReceiver: requestId doesn't match");
506             return false;
507         }
508 
509         return true;
510     }
511 
512     @Override
onDismissed(@iometricPrompt.DismissedReason int reason, @Nullable byte[] credentialAttestation, long requestId)513     public void onDismissed(@BiometricPrompt.DismissedReason int reason,
514             @Nullable byte[] credentialAttestation, long requestId) {
515         if (mCurrentDialog != null && requestId != mCurrentDialog.getRequestId()) {
516             Log.w(TAG, "requestId doesn't match, skip onDismissed");
517             return;
518         }
519 
520         sendResultAndCleanUp(reason, credentialAttestation);
521     }
522 
523     @Override
handleShowGlobalActionsMenu()524     public void handleShowGlobalActionsMenu() {
525         closeDialog("PowerMenu shown");
526     }
527 
528     /**
529      * @return where the UDFPS exists on the screen in pixels in portrait mode.
530      */
getUdfpsLocation()531     @Nullable public Point getUdfpsLocation() {
532         if (mUdfpsController == null || mUdfpsBounds == null) {
533             return null;
534         }
535         return new Point(mUdfpsBounds.centerX(), mUdfpsBounds.centerY());
536     }
537 
538     /**
539      * @return the radius of UDFPS on the screen in pixels
540      */
getUdfpsRadius()541     public float getUdfpsRadius() {
542         if (mUdfpsController == null || mUdfpsBounds == null) {
543             return -1;
544         }
545         return mUdfpsBounds.height() / 2f;
546     }
547 
548     /**
549      * Gets the cached scale factor representing the user's current resolution / the stable
550      * (default) resolution.
551      */
getScaleFactor()552     public float getScaleFactor() {
553         return mScaleFactor;
554     }
555 
556     /**
557      * Updates the current display info and cached scale factor & sensor locations.
558      * Getting the display info is a relatively expensive call, so avoid superfluous calls.
559      */
updateSensorLocations()560     private void updateSensorLocations() {
561         mDisplay.getDisplayInfo(mCachedDisplayInfo);
562         mScaleFactor = mUdfpsUtils.getScaleFactor(mCachedDisplayInfo);
563         updateUdfpsLocation();
564         updateFingerprintLocation();
565     }
566     /**
567      * @return where the fingerprint sensor exists in pixels in its natural orientation.
568      * Devices without location configs will use the default value even if they don't have a
569      * fingerprint sensor.
570      *
571      * May return null if the fingerprint sensor isn't available yet.
572      */
getFingerprintSensorLocationInNaturalOrientation()573     @Nullable private Point getFingerprintSensorLocationInNaturalOrientation() {
574         if (getUdfpsLocation() != null) {
575             return getUdfpsLocation();
576         } else {
577             int xFpLocation = mCachedDisplayInfo.getNaturalWidth() / 2;
578             try {
579                 xFpLocation = mContext.getResources().getDimensionPixelSize(
580                         com.android.systemui.res.R.dimen
581                                 .physical_fingerprint_sensor_center_screen_location_x);
582             } catch (Resources.NotFoundException e) {
583             }
584 
585             return new Point(
586                     (int) (xFpLocation * mScaleFactor),
587                     (int) (mContext.getResources().getDimensionPixelSize(
588                             com.android.systemui.res.R.dimen
589                                     .physical_fingerprint_sensor_center_screen_location_y)
590                             * mScaleFactor)
591             );
592         }
593     }
594 
595     /**
596      * @return where the fingerprint sensor exists in pixels exists the current device orientation.
597      * Devices without location configs will use the default value even if they don't have a
598      * fingerprint sensor.
599      */
getFingerprintSensorLocation()600     @Nullable public Point getFingerprintSensorLocation() {
601         return mFingerprintSensorLocation;
602     }
603 
updateFingerprintLocation()604     private void updateFingerprintLocation() {
605         if (mFpProps == null) {
606             mFingerprintSensorLocation = null;
607         } else {
608             mFingerprintSensorLocation = rotateToCurrentOrientation(
609                     getFingerprintSensorLocationInNaturalOrientation(),
610                     mCachedDisplayInfo);
611         }
612 
613         for (final Callback cb : mCallbacks) {
614             cb.onFingerprintLocationChanged();
615         }
616     }
617 
618     /** Get FP sensor properties */
getFingerprintProperties()619     public @Nullable List<FingerprintSensorPropertiesInternal> getFingerprintProperties() {
620         return mFpProps;
621     }
622 
623     /**
624      * @param inOutPoint point on the display in pixels. Going in, represents the point
625      *                   in the device's natural orientation. Going out, represents
626      *                   the point in the display's current orientation.
627      * @param displayInfo currently display information to use to rotate the point
628      */
629     @VisibleForTesting
rotateToCurrentOrientation(Point inOutPoint, DisplayInfo displayInfo)630     protected Point rotateToCurrentOrientation(Point inOutPoint, DisplayInfo displayInfo) {
631         RotationUtils.rotatePoint(
632                 inOutPoint,
633                 displayInfo.rotation,
634                 displayInfo.getNaturalWidth(),
635                 displayInfo.getNaturalHeight()
636         );
637         return inOutPoint;
638     }
639 
640     /**
641      * Requests fingerprint scan.
642      *
643      * @param screenX X position of long press
644      * @param screenY Y position of long press
645      * @param major length of the major axis. See {@link MotionEvent#AXIS_TOOL_MAJOR}.
646      * @param minor length of the minor axis. See {@link MotionEvent#AXIS_TOOL_MINOR}.
647      */
onAodInterrupt(int screenX, int screenY, float major, float minor)648     public void onAodInterrupt(int screenX, int screenY, float major, float minor) {
649         if (mUdfpsController == null) {
650             return;
651         }
652         mUdfpsController.onAodInterrupt(screenX, screenY, major, minor);
653     }
654 
sendResultAndCleanUp(@iometricPrompt.DismissedReason int reason, @Nullable byte[] credentialAttestation)655     private void sendResultAndCleanUp(@BiometricPrompt.DismissedReason int reason,
656             @Nullable byte[] credentialAttestation) {
657         if (mReceiver == null) {
658             Log.e(TAG, "sendResultAndCleanUp: Receiver is null");
659             return;
660         }
661 
662         try {
663             mReceiver.onDialogDismissed(reason, credentialAttestation);
664         } catch (RemoteException e) {
665             Log.w(TAG, "Remote exception", e);
666         }
667         onDialogDismissed(reason);
668     }
669     @Inject
AuthController(@ain Context context, @Application CoroutineScope applicationCoroutineScope, Execution execution, CommandQueue commandQueue, ActivityTaskManager activityTaskManager, @NonNull @Main WindowManager windowManager, @Nullable FingerprintManager fingerprintManager, @Nullable FaceManager faceManager, Optional<AuthContextPlugins> contextPlugins, Provider<UdfpsController> udfpsControllerFactory, @NonNull DisplayManager displayManager, @NonNull WakefulnessLifecycle wakefulnessLifecycle, @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils, @NonNull Lazy<UdfpsLogger> udfpsLogger, @NonNull Lazy<LogContextInteractor> logContextInteractor, @NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider, @NonNull Provider<CredentialViewModel> credentialViewModelProvider, @NonNull Provider<PromptViewModel> promptViewModelProvider, @NonNull InteractionJankMonitor jankMonitor, @Main Handler handler, @Background DelayableExecutor bgExecutor, @NonNull UdfpsUtils udfpsUtils, @NonNull VibratorHelper vibratorHelper, @NonNull KeyguardManager keyguardManager, @NonNull MSDLPlayer msdlPlayer, WindowManagerProvider windowManagerProvider)670     public AuthController(@Main Context context,
671             @Application CoroutineScope applicationCoroutineScope,
672             Execution execution,
673             CommandQueue commandQueue,
674             ActivityTaskManager activityTaskManager,
675             @NonNull @Main WindowManager windowManager,
676             @Nullable FingerprintManager fingerprintManager,
677             @Nullable FaceManager faceManager,
678             Optional<AuthContextPlugins> contextPlugins,
679             Provider<UdfpsController> udfpsControllerFactory,
680             @NonNull DisplayManager displayManager,
681             @NonNull WakefulnessLifecycle wakefulnessLifecycle,
682             @NonNull UserManager userManager,
683             @NonNull LockPatternUtils lockPatternUtils,
684             @NonNull Lazy<UdfpsLogger> udfpsLogger,
685             @NonNull Lazy<LogContextInteractor> logContextInteractor,
686             @NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider,
687             @NonNull Provider<CredentialViewModel> credentialViewModelProvider,
688             @NonNull Provider<PromptViewModel> promptViewModelProvider,
689             @NonNull InteractionJankMonitor jankMonitor,
690             @Main Handler handler,
691             @Background DelayableExecutor bgExecutor,
692             @NonNull UdfpsUtils udfpsUtils,
693             @NonNull VibratorHelper vibratorHelper,
694             @NonNull KeyguardManager keyguardManager,
695             @NonNull MSDLPlayer msdlPlayer,
696             WindowManagerProvider windowManagerProvider) {
697         mContext = context;
698         mExecution = execution;
699         mUserManager = userManager;
700         mLockPatternUtils = lockPatternUtils;
701         mHandler = handler;
702         mBackgroundExecutor = bgExecutor;
703         mCommandQueue = commandQueue;
704         mActivityTaskManager = activityTaskManager;
705         mFingerprintManager = fingerprintManager;
706         mFaceManager = faceManager;
707         mContextPlugins = contAuthPlugin() ? contextPlugins.orElse(null) : null;
708         mUdfpsControllerFactory = udfpsControllerFactory;
709         mUdfpsLogger = udfpsLogger;
710         mDisplayManager = displayManager;
711         mWindowManager = windowManager;
712         mInteractionJankMonitor = jankMonitor;
713         mUdfpsEnrolledForUser = new SparseBooleanArray();
714         mSfpsEnrolledForUser = new SparseBooleanArray();
715         mFaceEnrolledForUser = new SparseBooleanArray();
716         mUdfpsUtils = udfpsUtils;
717         mApplicationCoroutineScope = applicationCoroutineScope;
718         mVibratorHelper = vibratorHelper;
719         mMSDLPlayer = msdlPlayer;
720 
721         mLogContextInteractor = logContextInteractor;
722         mPromptSelectorInteractor = promptSelectorInteractorProvider;
723         mPromptViewModelProvider = promptViewModelProvider;
724         mCredentialViewModelProvider = credentialViewModelProvider;
725 
726         keyguardManager.addKeyguardLockedStateListener(
727                 context.getMainExecutor(),
728                 isKeyguardLocked -> {
729                     if (isKeyguardLocked) {
730                         closeDialog("Device lock");
731                     }
732                 }
733         );
734 
735         mOrientationListener = new BiometricDisplayListener(
736                 context,
737                 mDisplayManager,
738                 mHandler,
739                 BiometricDisplayListener.SensorType.Generic.INSTANCE,
740                 () -> {
741                     onOrientationChanged();
742                     return Unit.INSTANCE;
743                 });
744 
745         mWakefulnessLifecycle = wakefulnessLifecycle;
746 
747         mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
748 
749         mDisplay = mContext.getDisplay();
750         updateSensorLocations();
751 
752         IntentFilter filter = new IntentFilter();
753         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
754         context.registerReceiver(mBroadcastReceiver, filter, Context.RECEIVER_EXPORTED_UNAUDITED);
755         mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
756 
757         mWindowManagerProvider = windowManagerProvider;
758     }
759 
760     // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this.
761     // This is not combined with updateFingerprintLocation because this is invoked directly from
762     // UdfpsController, only when it cares about a rotation change. The implications of calling
763     // updateFingerprintLocation in such a case are unclear.
updateUdfpsLocation()764     private void updateUdfpsLocation() {
765         if (mUdfpsController != null) {
766             final FingerprintSensorPropertiesInternal udfpsProp = mUdfpsProps.get(0);
767 
768             final Rect previousUdfpsBounds = mUdfpsBounds;
769             final UdfpsOverlayParams previousUdfpsOverlayParams = mUdfpsOverlayParams;
770 
771             mUdfpsBounds = udfpsProp.getLocation().getRect();
772             mUdfpsBounds.scale(mScaleFactor);
773 
774             final Rect overlayBounds = new Rect(
775                     0, /* left */
776                     mCachedDisplayInfo.getNaturalHeight() / 2, /* top */
777                     mCachedDisplayInfo.getNaturalWidth(), /* right */
778                     mCachedDisplayInfo.getNaturalHeight() /* bottom */);
779 
780             mUdfpsOverlayParams = new UdfpsOverlayParams(
781                     mUdfpsBounds,
782                     overlayBounds,
783                     mCachedDisplayInfo.getNaturalWidth(),
784                     mCachedDisplayInfo.getNaturalHeight(),
785                     mScaleFactor,
786                     mCachedDisplayInfo.rotation,
787                     udfpsProp.sensorType);
788 
789             mUdfpsController.updateOverlayParams(udfpsProp, mUdfpsOverlayParams);
790             if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds) || !Objects.equals(
791                     previousUdfpsOverlayParams, mUdfpsOverlayParams)) {
792                 for (Callback cb : mCallbacks) {
793                     cb.onUdfpsLocationChanged(mUdfpsOverlayParams);
794                 }
795             }
796         }
797     }
798 
799     @SuppressWarnings("deprecation")
800     @Override
start()801     public void start() {
802         mCommandQueue.addCallback(this);
803 
804         if (mFingerprintManager != null) {
805             mFingerprintManager.addAuthenticatorsRegisteredCallback(
806                     new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
807                         @Override
808                         public void onAllAuthenticatorsRegistered(
809                                 List<FingerprintSensorPropertiesInternal> sensors) {
810                             mHandler.post(() ->
811                                     handleAllFingerprintAuthenticatorsRegistered(sensors));
812                         }
813                     });
814         }
815         if (mFaceManager != null) {
816             mFaceManager.addAuthenticatorsRegisteredCallback(
817                     new IFaceAuthenticatorsRegisteredCallback.Stub() {
818                         @Override
819                         public void onAllAuthenticatorsRegistered(
820                                 List<FaceSensorPropertiesInternal> sensors) {
821                             mHandler.post(() ->
822                                     handleAllFaceAuthenticatorsRegistered(sensors));
823                         }
824                     }
825             );
826         }
827 
828         mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
829         mOrientationListener.enable();
830         updateSensorLocations();
831 
832         if (mContextPlugins != null) {
833             mContextPlugins.activate();
834         }
835     }
836 
837     @Override
setBiometricContextListener(IBiometricContextListener listener)838     public void setBiometricContextListener(IBiometricContextListener listener) {
839         if (mBiometricContextListenerJob != null) {
840             mBiometricContextListenerJob.cancel(null);
841         }
842         mBiometricContextListenerJob =
843                 mLogContextInteractor.get().addBiometricContextListener(listener);
844     }
845 
846     /**
847      * Stores the callback received from
848      * {@link com.android.server.display.mode.DisplayModeDirector}.
849      *
850      * DisplayModeDirector implements {@link IUdfpsRefreshRateRequestCallback}
851      * and registers it with this class by calling
852      * {@link CommandQueue#setUdfpsRefreshRateCallback(IUdfpsRefreshRateRequestCallback)}.
853      */
854     @Override
setUdfpsRefreshRateCallback(IUdfpsRefreshRateRequestCallback callback)855     public void setUdfpsRefreshRateCallback(IUdfpsRefreshRateRequestCallback callback) {
856         mUdfpsRefreshRateRequestCallback = callback;
857     }
858 
859     /**
860      * @return IUdfpsRefreshRateRequestCallback that can be set by DisplayModeDirector.
861      */
getUdfpsRefreshRateCallback()862     @Nullable public IUdfpsRefreshRateRequestCallback getUdfpsRefreshRateCallback() {
863         return mUdfpsRefreshRateRequestCallback;
864     }
865 
866     /**
867      * Requests (or stops requesting) the max refresh rate. This can override user settings
868      * for the max refresh rate.
869      */
requestMaxRefreshRate(boolean request)870     public void requestMaxRefreshRate(boolean request) throws RemoteException {
871         if (mUdfpsRefreshRateRequestCallback == null) {
872             mUdfpsLogger.get().log(
873                     "PreAuthRefreshRate",
874                     "skip request - refreshRateCallback is null",
875                     LogLevel.DEBUG
876             );
877             return;
878         }
879         mUdfpsLogger.get().requestMaxRefreshRate(request);
880         mUdfpsRefreshRateRequestCallback.onAuthenticationPossible(mContext.getDisplayId(), request);
881     }
882 
883     @Override
showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, long operationId, String opPackageName, long requestId)884     public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
885             int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
886             int userId, long operationId, String opPackageName, long requestId) {
887         @Authenticators.Types final int authenticators = promptInfo.getAuthenticators();
888 
889         if (DEBUG) {
890             StringBuilder ids = new StringBuilder();
891             for (int sensorId : sensorIds) {
892                 ids.append(sensorId).append(" ");
893             }
894             Log.d(TAG, "showAuthenticationDialog, authenticators: " + authenticators
895                     + ", sensorIds: " + ids.toString()
896                     + ", credentialAllowed: " + credentialAllowed
897                     + ", requireConfirmation: " + requireConfirmation
898                     + ", operationId: " + operationId
899                     + ", requestId: " + requestId);
900         }
901         SomeArgs args = SomeArgs.obtain();
902         args.arg1 = promptInfo;
903         args.arg2 = receiver;
904         args.arg3 = sensorIds;
905         args.arg4 = credentialAllowed;
906         args.arg5 = requireConfirmation;
907         args.argi1 = userId;
908         args.arg6 = opPackageName;
909         args.argl1 = operationId;
910         args.argl2 = requestId;
911 
912         boolean skipAnimation = false;
913         if (mCurrentDialog != null) {
914             Log.w(TAG, "mCurrentDialog: " + mCurrentDialog);
915             skipAnimation = true;
916         }
917 
918         showDialog(args, skipAnimation, mPromptViewModelProvider.get());
919     }
920 
921     /**
922      * Only called via BiometricService for the biometric prompt. Will not be called for
923      * authentication directly requested through FingerprintManager. For
924      * example, KeyguardUpdateMonitor has its own {@link FingerprintManager.AuthenticationCallback}.
925      */
926     @Override
onBiometricAuthenticated(@odality int modality)927     public void onBiometricAuthenticated(@Modality int modality) {
928         if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: ");
929 
930         if (mCurrentDialog != null) {
931             mCurrentDialog.onAuthenticationSucceeded(modality);
932         } else {
933             Log.w(TAG, "onBiometricAuthenticated callback but dialog gone");
934         }
935     }
936 
937     @Override
onBiometricHelp(@odality int modality, String message)938     public void onBiometricHelp(@Modality int modality, String message) {
939         if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
940 
941         if (mCurrentDialog != null) {
942             mCurrentDialog.onHelp(modality, message);
943         } else {
944             Log.w(TAG, "onBiometricHelp callback but dialog gone");
945         }
946     }
947 
948     @Nullable
getUdfpsProps()949     public List<FingerprintSensorPropertiesInternal> getUdfpsProps() {
950         return mUdfpsProps;
951     }
952 
953     @Nullable
getSfpsProps()954     public List<FingerprintSensorPropertiesInternal> getSfpsProps() {
955         return mSidefpsProps;
956     }
957 
958     /**
959      * @return true if udfps HW is supported on this device. Can return true even if the user has
960      * not enrolled udfps. This may be false if called before onAllAuthenticatorsRegistered.
961      */
isUdfpsSupported()962     public boolean isUdfpsSupported() {
963         return getUdfpsProps() != null && !getUdfpsProps().isEmpty();
964     }
965 
966     /**
967      * @return true if optical udfps HW is supported on this device. Can return true even if
968      * the user has not enrolled udfps. This may be false if called before
969      * onAllAuthenticatorsRegistered.
970      */
isOpticalUdfpsSupported()971     public boolean isOpticalUdfpsSupported() {
972         return getUdfpsProps() != null && !getUdfpsProps().isEmpty() && getUdfpsProps()
973                 .get(0).isOpticalUdfps();
974     }
975 
976     /**
977      * @return true if ultrasonic udfps HW is supported on this device. Can return true even if
978      * the user has not enrolled udfps. This may be false if called before
979      * onAllAuthenticatorsRegistered.
980      */
isUltrasonicUdfpsSupported()981     public boolean isUltrasonicUdfpsSupported() {
982         return getUdfpsProps() != null && !getUdfpsProps().isEmpty() && getUdfpsProps()
983                 .get(0).isUltrasonicUdfps();
984     }
985 
986     /**
987      * @return true if sfps HW is supported on this device. Can return true even if the user has
988      * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered.
989      */
isSfpsSupported()990     public boolean isSfpsSupported() {
991         return getSfpsProps() != null && !getSfpsProps().isEmpty();
992     }
993 
994     /**
995      * @return true if rear fps HW is supported on this device. Can return true even if the user has
996      * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered.
997      */
isRearFpsSupported()998     public boolean isRearFpsSupported() {
999         if (mFpProps != null) {
1000             for (FingerprintSensorPropertiesInternal prop: mFpProps) {
1001                 if (prop.sensorType == TYPE_REAR) {
1002                     return true;
1003                 }
1004             }
1005         }
1006         return false;
1007     }
1008 
getNotRecognizedString(@odality int modality)1009     private String getNotRecognizedString(@Modality int modality) {
1010         final int messageRes;
1011         final int userId = mCurrentDialogArgs.argi1;
1012         if (isFaceAuthEnrolled(userId) && isFingerprintEnrolled(userId)) {
1013             messageRes = modality == TYPE_FACE
1014                     ? R.string.fingerprint_dialog_use_fingerprint_instead
1015                     : R.string.fingerprint_error_not_match;
1016         } else {
1017             messageRes = R.string.biometric_not_recognized;
1018         }
1019         return mContext.getString(messageRes);
1020     }
1021 
getErrorString(@odality int modality, int error, int vendorCode)1022     private String getErrorString(@Modality int modality, int error, int vendorCode) {
1023         switch (modality) {
1024             case TYPE_FACE:
1025                 return FaceManager.getErrorString(mContext, error, vendorCode);
1026 
1027             case TYPE_FINGERPRINT:
1028                 return FingerprintManager.getErrorString(mContext, error, vendorCode);
1029 
1030             default:
1031                 return "";
1032         }
1033     }
1034 
1035     /**
1036      * Only called via BiometricService for the biometric prompt. Will not be called for
1037      * authentication directly requested through FingerprintManager. For
1038      * example, KeyguardUpdateMonitor has its own {@link FingerprintManager.AuthenticationCallback}.
1039      */
1040     @Override
onBiometricError(@odality int modality, int error, int vendorCode)1041     public void onBiometricError(@Modality int modality, int error, int vendorCode) {
1042         if (DEBUG) {
1043             Log.d(TAG, String.format("onBiometricError(%d, %d, %d)", modality, error, vendorCode));
1044         }
1045 
1046         final boolean isLockout = (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT)
1047                 || (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT);
1048 
1049         boolean isCameraPrivacyEnabled = false;
1050         if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE
1051                 && mSensorPrivacyManager.isSensorPrivacyEnabled(
1052                 SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, SensorPrivacyManager.Sensors.CAMERA)) {
1053             isCameraPrivacyEnabled = true;
1054         }
1055         // TODO(b/141025588): Create separate methods for handling hard and soft errors.
1056         final boolean isSoftError = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED
1057                 || error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT
1058                 || error == BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL
1059                 || isCameraPrivacyEnabled);
1060         if (mCurrentDialog != null) {
1061             if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) {
1062                 if (DEBUG) Log.d(TAG, "onBiometricError, lockout");
1063                 mCurrentDialog.animateToCredentialUI(true /* isError */);
1064             } else if (isSoftError) {
1065                 final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED
1066                         || error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT)
1067                         ? getNotRecognizedString(modality)
1068                         : getErrorString(modality, error, vendorCode);
1069                 if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
1070                 // The camera privacy error can return before the prompt initializes its state,
1071                 // causing the prompt to appear to endlessly authenticate. Add a small delay
1072                 // to stop this.
1073                 if (isCameraPrivacyEnabled) {
1074                     mHandler.postDelayed(() -> {
1075                         mCurrentDialog.onAuthenticationFailed(modality,
1076                                 mContext.getString(R.string.face_sensor_privacy_enabled));
1077                     }, SENSOR_PRIVACY_DELAY);
1078                 } else {
1079                     mCurrentDialog.onAuthenticationFailed(modality, errorMessage);
1080                 }
1081             } else {
1082                 final String errorMessage = getErrorString(modality, error, vendorCode);
1083                 if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
1084                 mCurrentDialog.onError(modality, errorMessage);
1085             }
1086 
1087         } else {
1088             Log.w(TAG, "onBiometricError callback but dialog is gone");
1089         }
1090     }
1091 
1092     @Override
hideAuthenticationDialog(long requestId)1093     public void hideAuthenticationDialog(long requestId) {
1094         if (DEBUG) Log.d(TAG, "hideAuthenticationDialog: " + mCurrentDialog);
1095 
1096         if (mCurrentDialog == null) {
1097             // Could be possible if the caller canceled authentication after credential success
1098             // but before the client was notified.
1099             if (DEBUG) Log.d(TAG, "dialog already gone");
1100             return;
1101         }
1102         if (requestId != mCurrentDialog.getRequestId()) {
1103             Log.w(TAG, "ignore - ids do not match: " + requestId + " current: "
1104                     + mCurrentDialog.getRequestId());
1105             return;
1106         }
1107 
1108         mCurrentDialog.dismissFromSystemServer();
1109         for (Callback cb : mCallbacks) {
1110             cb.onBiometricPromptDismissed();
1111         }
1112 
1113         // BiometricService will have already sent the callback to the client in this case.
1114         // This avoids a round trip to SystemUI. So, just dismiss the dialog and we're done.
1115         mCurrentDialog = null;
1116     }
1117 
1118     /**
1119      * Whether the user's finger is currently on udfps attempting to authenticate.
1120      */
isUdfpsFingerDown()1121     public boolean isUdfpsFingerDown() {
1122         if (mUdfpsController == null)  {
1123             return false;
1124         }
1125 
1126         return mUdfpsController.isFingerDown();
1127     }
1128 
1129     /**
1130      * Whether the passed userId has enrolled face auth.
1131      */
isFaceAuthEnrolled(int userId)1132     public boolean isFaceAuthEnrolled(int userId) {
1133         if (mFaceProps == null) {
1134             return false;
1135         }
1136 
1137         return mFaceEnrolledForUser.get(userId);
1138     }
1139 
1140     /**
1141      * Does the provided user have at least one optical udfps fingerprint enrolled?
1142      */
isOpticalUdfpsEnrolled(int userId)1143     public boolean isOpticalUdfpsEnrolled(int userId) {
1144         return isUdfpsEnrolled(userId)
1145                 && mUdfpsProps != null
1146                 && mUdfpsProps.get(0).sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
1147     }
1148 
1149     /**
1150      * Whether the passed userId has enrolled UDFPS.
1151      */
isUdfpsEnrolled(int userId)1152     public boolean isUdfpsEnrolled(int userId) {
1153         if (mUdfpsController == null) {
1154             return false;
1155         }
1156 
1157         return mUdfpsEnrolledForUser.get(userId);
1158     }
1159 
1160     /**
1161      * Whether the passed userId has enrolled SFPS.
1162      */
isSfpsEnrolled(int userId)1163     public boolean isSfpsEnrolled(int userId) {
1164         if (mSidefpsProps == null) {
1165             return false;
1166         }
1167 
1168         return mSfpsEnrolledForUser.get(userId);
1169     }
1170 
1171     /** If BiometricPrompt is currently being shown to the user. */
isShowing()1172     public boolean isShowing() {
1173         return mCurrentDialog != null;
1174     }
1175 
1176     /**
1177      * Whether the passed userId has enrolled at least one fingerprint.
1178      */
isFingerprintEnrolled(int userId)1179     public boolean isFingerprintEnrolled(int userId) {
1180         return mFpEnrolledForUser.getOrDefault(userId, false);
1181     }
1182 
showDialog(SomeArgs args, boolean skipAnimation, @Nullable PromptViewModel viewModel)1183     private void showDialog(SomeArgs args, boolean skipAnimation,
1184             @Nullable PromptViewModel viewModel) {
1185         mCurrentDialogArgs = args;
1186 
1187         final PromptInfo promptInfo = (PromptInfo) args.arg1;
1188         final int[] sensorIds = (int[]) args.arg3;
1189 
1190         // TODO(b/251476085): remove these unused parameters (replaced with SSOT elsewhere)
1191         final boolean credentialAllowed = (boolean) args.arg4;
1192         final boolean requireConfirmation = (boolean) args.arg5;
1193 
1194         final int userId = args.argi1;
1195         final String opPackageName = (String) args.arg6;
1196         final long operationId = args.argl1;
1197         final long requestId = args.argl2;
1198 
1199         // Create a new dialog but do not replace the current one yet.
1200         final AuthContainerView newDialog = buildDialog(
1201                 mBackgroundExecutor,
1202                 promptInfo,
1203                 requireConfirmation,
1204                 userId,
1205                 sensorIds,
1206                 opPackageName,
1207                 skipAnimation,
1208                 operationId,
1209                 requestId,
1210                 mWakefulnessLifecycle,
1211                 mUserManager,
1212                 mLockPatternUtils,
1213                 viewModel);
1214 
1215         if (newDialog == null) {
1216             Log.e(TAG, "Unsupported type configuration");
1217             return;
1218         }
1219 
1220         if (DEBUG) {
1221             Log.d(TAG, "userId: " + userId
1222                     + " mCurrentDialog: " + mCurrentDialog
1223                     + " newDialog: " + newDialog);
1224         }
1225 
1226         if (mCurrentDialog != null) {
1227             // If somehow we're asked to show a dialog, the old one doesn't need to be animated
1228             // away. This can happen if the app cancels and re-starts auth during configuration
1229             // change. This is ugly because we also have to do things on onConfigurationChanged
1230             // here.
1231             mCurrentDialog.dismissWithoutCallback(false /* animate */);
1232         }
1233 
1234         mReceiver = (IBiometricSysuiReceiver) args.arg2;
1235         for (Callback cb : mCallbacks) {
1236             cb.onBiometricPromptShown();
1237         }
1238         mCurrentDialog = newDialog;
1239 
1240         // TODO(b/353597496): We should check whether |allowBackgroundAuthentication| should be
1241         //  removed.
1242         if (!promptInfo.isAllowBackgroundAuthentication() && isOwnerInBackground()) {
1243             cancelIfOwnerIsNotInForeground();
1244         } else {
1245             WindowManager wm = getWindowManagerForUser(userId);
1246             if (wm != null) {
1247                 mCurrentDialog.show(wm);
1248             } else {
1249                 closeDialog(BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM,
1250                         "unable to get WM instance for user");
1251             }
1252         }
1253     }
1254 
1255     @Nullable
getWindowManagerForUser(int userId)1256     private WindowManager getWindowManagerForUser(int userId) {
1257         if (!mUserManager.isVisibleBackgroundUsersSupported()) {
1258             return mWindowManager;
1259         }
1260         UserManager um = mContext.createContextAsUser(UserHandle.of(userId),
1261                 0 /* flags */).getSystemService(UserManager.class);
1262         if (um == null) {
1263             Log.e(TAG, "unable to get UserManager for user=" + userId);
1264             return null;
1265         }
1266         if (!um.isUserVisible()) {
1267             // not visible user - use default window manager
1268             return mWindowManager;
1269         }
1270         int displayId = um.getMainDisplayIdAssignedToUser();
1271         if (displayId == INVALID_DISPLAY) {
1272             Log.e(TAG, "unable to get display assigned to user=" + userId);
1273             return null;
1274         }
1275         Display display = mDisplayManager.getDisplay(displayId);
1276         if (display == null) {
1277             Log.e(TAG, "unable to get Display for user=" + userId);
1278             return null;
1279         }
1280         return mWindowManagerProvider.getWindowManager(mContext.createDisplayContext(display));
1281     }
1282 
onDialogDismissed(@iometricPrompt.DismissedReason int reason)1283     private void onDialogDismissed(@BiometricPrompt.DismissedReason int reason) {
1284         if (DEBUG) Log.d(TAG, "onDialogDismissed: " + reason);
1285         if (mCurrentDialog == null) {
1286             Log.w(TAG, "Dialog already dismissed");
1287         }
1288 
1289         for (Callback cb : mCallbacks) {
1290             cb.onBiometricPromptDismissed();
1291         }
1292 
1293         mReceiver = null;
1294         mCurrentDialog = null;
1295     }
1296 
1297     @Override
onConfigChanged(Configuration newConfig)1298     public void onConfigChanged(Configuration newConfig) {
1299         updateSensorLocations();
1300 
1301         // TODO(b/287311775): consider removing this to retain the UI cleanly vs re-creating
1302         if (mCurrentDialog != null) {
1303             final PromptViewModel viewModel = mCurrentDialog.getViewModel();
1304             mCurrentDialog.dismissWithoutCallback(false /* animate */);
1305             mCurrentDialog = null;
1306             showDialog(mCurrentDialogArgs, true /* skipAnimation */, viewModel);
1307         }
1308     }
1309 
onOrientationChanged()1310     private void onOrientationChanged() {
1311         updateSensorLocations();
1312         if (mCurrentDialog != null) {
1313             mCurrentDialog.onOrientationChanged();
1314         }
1315     }
1316 
buildDialog(@ackground DelayableExecutor bgExecutor, PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds, String opPackageName, boolean skipIntro, long operationId, long requestId, @NonNull WakefulnessLifecycle wakefulnessLifecycle, @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils, @NonNull PromptViewModel viewModel)1317     protected AuthContainerView buildDialog(@Background DelayableExecutor bgExecutor,
1318             PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds,
1319             String opPackageName, boolean skipIntro, long operationId, long requestId,
1320             @NonNull WakefulnessLifecycle wakefulnessLifecycle,
1321             @NonNull UserManager userManager,
1322             @NonNull LockPatternUtils lockPatternUtils,
1323             @NonNull PromptViewModel viewModel) {
1324         final AuthContainerView.Config config = new AuthContainerView.Config();
1325         config.mContext = mContext;
1326         config.mCallback = this;
1327         config.mPromptInfo = promptInfo;
1328         config.mRequireConfirmation = requireConfirmation;
1329         config.mUserId = userId;
1330         config.mOpPackageName = opPackageName;
1331         config.mSkipIntro = skipIntro;
1332         config.mOperationId = operationId;
1333         config.mRequestId = requestId;
1334         config.mSensorIds = sensorIds;
1335         config.mScaleProvider = this::getScaleFactor;
1336         return new AuthContainerView(config, mApplicationCoroutineScope, mFpProps, mFaceProps,
1337                 wakefulnessLifecycle, userManager, mContextPlugins, lockPatternUtils,
1338                 mInteractionJankMonitor, mPromptSelectorInteractor, viewModel,
1339                 mCredentialViewModelProvider, bgExecutor, mVibratorHelper, mMSDLPlayer);
1340     }
1341 
1342     @Override
dump(@onNull PrintWriter pw, @NonNull String[] args)1343     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
1344         final AuthContainerView dialog = mCurrentDialog;
1345         pw.println("  mCachedDisplayInfo=" + mCachedDisplayInfo);
1346         pw.println("  mScaleFactor=" + mScaleFactor);
1347         pw.println("  fingerprintSensorLocationInNaturalOrientation="
1348                 + getFingerprintSensorLocationInNaturalOrientation());
1349         pw.println("  fingerprintSensorLocation=" + getFingerprintSensorLocation());
1350         pw.println("  udfpsBounds=" + mUdfpsBounds);
1351         pw.println("  allFingerprintAuthenticatorsRegistered="
1352                 + mAllFingerprintAuthenticatorsRegistered);
1353         pw.println("  currentDialog=" + dialog);
1354         if (dialog != null) {
1355             dialog.dump(pw, args);
1356         }
1357     }
1358 
1359     /**
1360      * Provides a float that represents the resolution scale(if the controller is for UDFPS).
1361      */
1362     public interface ScaleFactorProvider {
1363         /**
1364          * Returns a float representing the scaled resolution(if the controller if for UDFPS).
1365          */
provide()1366         float provide();
1367     }
1368 
1369     /**
1370      * AuthController callback used to receive signal for when biometric authenticators are
1371      * registered.
1372      */
1373     public interface Callback {
1374         /**
1375          * Called when authenticators are registered. If authenticators are already
1376          * registered before this call, this callback will never be triggered.
1377          */
onAllAuthenticatorsRegistered(@odality int modality)1378         default void onAllAuthenticatorsRegistered(@Modality int modality) {}
1379 
1380         /**
1381          * Called when enrollments have changed. This is called after boot and on changes to
1382          * enrollment.
1383          */
onEnrollmentsChanged(@odality int modality)1384         default void onEnrollmentsChanged(@Modality int modality) {}
1385 
1386         /**
1387          * Called when enrollments have changed. This is called after boot and on changes to
1388          * enrollment.
1389          */
onEnrollmentsChanged( @onNull BiometricType biometricType, int userId, boolean hasEnrollments )1390         default void onEnrollmentsChanged(
1391                 @NonNull BiometricType biometricType,
1392                 int userId,
1393                 boolean hasEnrollments
1394         ) {}
1395 
1396         /**
1397          * Called when the biometric prompt starts showing.
1398          */
onBiometricPromptShown()1399         default void onBiometricPromptShown() {}
1400 
1401         /**
1402          * Called when the biometric prompt is no longer showing.
1403          */
onBiometricPromptDismissed()1404         default void onBiometricPromptDismissed() {}
1405 
1406         /**
1407          * Called when the location of the fingerprint sensor changes. The location in pixels can
1408          * change due to resolution changes.
1409          */
onFingerprintLocationChanged()1410         default void onFingerprintLocationChanged() {}
1411 
1412         /**
1413          * Called when the location of the under display fingerprint sensor changes. The location in
1414          * pixels can change due to resolution changes.
1415          *
1416          * On devices with UDFPS, this is always called alongside
1417          * {@link #onFingerprintLocationChanged}.
1418          */
onUdfpsLocationChanged(UdfpsOverlayParams udfpsOverlayParams)1419         default void onUdfpsLocationChanged(UdfpsOverlayParams udfpsOverlayParams) {}
1420     }
1421 }
1422