diff --git a/packages/SystemUI/res-keyguard/drawable/circle_white.xml b/packages/SystemUI/res-keyguard/drawable/circle_white.xml
new file mode 100644
index 0000000000000..d1b20979c29ec
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/circle_white.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/disabled_udfps_view.xml b/packages/SystemUI/res/layout/disabled_udfps_view.xml
new file mode 100644
index 0000000000000..aab86613ef45a
--- /dev/null
+++ b/packages/SystemUI/res/layout/disabled_udfps_view.xml
@@ -0,0 +1,24 @@
+
+
+
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index ccd235d54c0bc..c0788051efed4 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -1,4 +1,19 @@
+
implements Dumpable {
+ @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @NonNull private final KeyguardViewController mKeyguardViewController;
+ @NonNull private final StatusBarStateController mStatusBarStateController;
+
+ private boolean mIsDozing;
+ private boolean mIsBouncerShowing;
+ private boolean mIsKeyguardShowing;
+ private boolean mRunningFPS;
+ private boolean mAuthenticated;
+
+ private boolean mShowButton;
+
+ public DisabledUdfpsController(
+ @NonNull DisabledUdfpsView view,
+ @NonNull StatusBarStateController statusBarStateController,
+ @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
+ @NonNull AuthController authController,
+ @NonNull KeyguardViewController keyguardViewController
+ ) {
+ super(view);
+ mView.setOnClickListener(mOnClickListener);
+ mView.setSensorProperties(authController.getUdfpsProps().get(0));
+
+ mStatusBarStateController = statusBarStateController;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mKeyguardViewController = keyguardViewController;
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+ mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
+
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mIsKeyguardShowing = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+ mIsDozing = mStatusBarStateController.isDozing();
+ mAuthenticated = false;
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
+ mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ }
+
+ private void updateButtonVisibility() {
+ mShowButton = !mAuthenticated && !mIsDozing && mIsKeyguardShowing
+ && !mIsBouncerShowing && !mRunningFPS;
+ if (mShowButton) {
+ mView.setVisibility(View.VISIBLE);
+ } else {
+ mView.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("DisabledUdfpsController state:");
+ pw.println(" mShowBouncerButton: " + mShowButton);
+ pw.println(" mIsDozing: " + mIsDozing);
+ pw.println(" mIsKeyguardShowing: " + mIsKeyguardShowing);
+ pw.println(" mIsBouncerShowing: " + mIsBouncerShowing);
+ pw.println(" mRunningFPS: " + mRunningFPS);
+ pw.println(" mAuthenticated: " + mAuthenticated);
+ }
+
+ private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mKeyguardViewController.showBouncer(/* scrim */ true);
+ }
+ };
+
+ private StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ mIsKeyguardShowing = newState == StatusBarState.KEYGUARD;
+ updateButtonVisibility();
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ mIsDozing = isDozing;
+ updateButtonVisibility();
+ }
+ };
+
+ private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onKeyguardBouncerChanged(boolean bouncer) {
+ mIsBouncerShowing = bouncer;
+ updateButtonVisibility();
+ }
+
+ @Override
+ public void onBiometricRunningStateChanged(boolean running,
+ BiometricSourceType biometricSourceType) {
+ mRunningFPS = running && biometricSourceType == FINGERPRINT;
+ updateButtonVisibility();
+ }
+
+ @Override
+ public void onUserUnlocked() {
+ mAuthenticated = true;
+ updateButtonVisibility();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java
new file mode 100644
index 0000000000000..d8ab780eb6bd8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 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.keyguard;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.RectF;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.util.AttributeSet;
+import android.view.Surface;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+/**
+ * A full screen view with an oval target where the UDFPS sensor is.
+ * Controlled by {@link DisabledUdfpsController}.
+ */
+public class DisabledUdfpsView extends Button {
+ @NonNull private final RectF mSensorRect;
+ @NonNull private final Context mContext;
+
+ // Used to obtain the sensor location.
+ @NonNull private FingerprintSensorPropertiesInternal mSensorProps;
+
+ public DisabledUdfpsView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ mSensorRect = new RectF();
+ }
+
+ public void setSensorProperties(@NonNull FingerprintSensorPropertiesInternal properties) {
+ mSensorProps = properties;
+ }
+
+ // The "h" and "w" are the display's height and width relative to its current rotation.
+ private void updateSensorRect(int h, int w) {
+ // mSensorProps coordinates assume portrait mode.
+ mSensorRect.set(mSensorProps.sensorLocationX - mSensorProps.sensorRadius,
+ mSensorProps.sensorLocationY - mSensorProps.sensorRadius,
+ mSensorProps.sensorLocationX + mSensorProps.sensorRadius,
+ mSensorProps.sensorLocationY + mSensorProps.sensorRadius);
+
+ // Transform mSensorRect if the device is in landscape mode.
+ switch (mContext.getDisplay().getRotation()) {
+ case Surface.ROTATION_90:
+ mSensorRect.set(mSensorRect.top, h - mSensorRect.right, mSensorRect.bottom,
+ h - mSensorRect.left);
+ break;
+ case Surface.ROTATION_270:
+ mSensorRect.set(w - mSensorRect.bottom, mSensorRect.left, w - mSensorRect.top,
+ mSensorRect.right);
+ break;
+ default:
+ // Do nothing to stay in portrait mode.
+ }
+
+ setX(mSensorRect.left);
+ setY(mSensorRect.top);
+ setLayoutParams(new FrameLayout.LayoutParams(
+ (int) (mSensorRect.right - mSensorRect.left),
+ (int) (mSensorRect.bottom - mSensorRect.top)));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ // Always re-compute the layout regardless of whether "changed" is true. It is usually false
+ // when the device goes from landscape to seascape and vice versa, but mSensorRect and
+ // its dependencies need to be recalculated to stay at the same physical location on the
+ // screen.
+ final int w = getLayoutParams().width;
+ final int h = getLayoutParams().height;
+ updateSensorRect(h, w);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 611131f6e2168..a7e51951e9cd7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1925,6 +1925,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
// TODO: Add support for multiple fingerprint sensors, b/173730729
+ updateUdfpsEnrolled(getCurrentUser());
boolean shouldListenForFingerprint =
isUdfpsEnrolled() ? shouldListenForUdfps() : shouldListenForFingerprint();
boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
@@ -2137,7 +2138,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
int userId = getCurrentUser();
- updateUdfpsEnrolled(userId);
if (isUnlockWithFingerprintPossible(userId)) {
if (mFingerprintCancelSignal != null) {
mFingerprintCancelSignal.cancel();
@@ -2627,7 +2627,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Assert.isMainThread();
if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncerVisible + ")");
mBouncer = bouncerVisible == 1;
-
if (mBouncer) {
// If the bouncer is shown, always clear this flag. This can happen in the following
// situations: 1) Default camera with SHOW_WHEN_LOCKED is not chosen yet. 2) Secure
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 061d8cf1ab308..9edfee73936e9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -410,6 +410,11 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mCurrentDialog.onHelp(message);
}
+ @Nullable
+ public List getUdfpsProps() {
+ return mUdfpsProps;
+ }
+
private String getErrorString(int modality, int error, int vendorCode) {
switch (modality) {
case TYPE_FACE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index f7139aa2acce6..bb46172cd7143 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -68,6 +68,7 @@ import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.LatencyTracker;
+import com.android.keyguard.DisabledUdfpsController;
import com.android.keyguard.KeyguardClockSwitchController;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardStatusViewController;
@@ -256,7 +257,25 @@ public class NotificationPanelViewController extends PanelViewController {
mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
mDelayShowingKeyguardStatusBar = false;
}
- };
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ if (mDisabledUdfpsController == null
+ && mAuthController.getUdfpsRegion() != null
+ && mAuthController.isUdfpsEnrolled(
+ KeyguardUpdateMonitor.getCurrentUser())) {
+ LayoutInflater.from(mView.getContext())
+ .inflate(R.layout.disabled_udfps_view, mView);
+ mDisabledUdfpsController = new DisabledUdfpsController(
+ mView.findViewById(R.id.disabled_udfps_view),
+ mStatusBarStateController,
+ mUpdateMonitor,
+ mAuthController,
+ mStatusBarKeyguardViewManager);
+ mDisabledUdfpsController.init();
+ }
+ }
+ };
private final InjectionInflationController mInjectionInflationController;
private final PowerManager mPowerManager;
@@ -284,6 +303,7 @@ public class NotificationPanelViewController extends PanelViewController {
private QS mQs;
private FrameLayout mQsFrame;
private KeyguardStatusViewController mKeyguardStatusViewController;
+ private DisabledUdfpsController mDisabledUdfpsController;
private View mQsNavbarScrim;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
private boolean mAnimateNextPositionUpdate;
@@ -3044,6 +3064,9 @@ public class NotificationPanelViewController extends PanelViewController {
if (mKeyguardStatusBar != null) {
mKeyguardStatusBar.dump(fd, pw, args);
}
+ if (mDisabledUdfpsController != null) {
+ mDisabledUdfpsController.dump(fd, pw, args);
+ }
}
public boolean hasActiveClearableNotifications() {