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() {