Merge "Allow users to swipe up on bouncer to retry auth" into qt-dev
This commit is contained in:
@@ -19,8 +19,7 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false">
|
||||||
android:fitsSystemWindows="true">
|
|
||||||
|
|
||||||
<include
|
<include
|
||||||
style="@style/BouncerSecurityContainer"
|
style="@style/BouncerSecurityContainer"
|
||||||
|
|||||||
@@ -231,6 +231,13 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
|
|||||||
public void showUsabilityHint() {
|
public void showUsabilityHint() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean disallowInterceptTouch(MotionEvent event) {
|
||||||
|
mTempRect.set(mLockPatternView.getLeft(), mLockPatternView.getTop(),
|
||||||
|
mLockPatternView.getRight(), mLockPatternView.getBottom());
|
||||||
|
return mTempRect.contains((int) event.getX(), (int) event.getY());
|
||||||
|
}
|
||||||
|
|
||||||
/** TODO: hook this up */
|
/** TODO: hook this up */
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
if (DEBUG) Log.v(TAG, "Cleanup() called on " + this);
|
if (DEBUG) Log.v(TAG, "Cleanup() called on " + this);
|
||||||
|
|||||||
@@ -26,12 +26,18 @@ import android.util.AttributeSet;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.StatsLog;
|
import android.util.StatsLog;
|
||||||
|
import android.util.TypedValue;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.VelocityTracker;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
import androidx.dynamicanimation.animation.DynamicAnimation;
|
||||||
|
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||||
|
|
||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
@@ -60,6 +66,11 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
// Bouncer is dismissed due to sim card unlock code entered.
|
// Bouncer is dismissed due to sim card unlock code entered.
|
||||||
private static final int BOUNCER_DISMISS_SIM = 4;
|
private static final int BOUNCER_DISMISS_SIM = 4;
|
||||||
|
|
||||||
|
// Make the view move slower than the finger, as if the spring were applying force.
|
||||||
|
private static final float TOUCH_Y_MULTIPLIER = 0.25f;
|
||||||
|
// How much you need to drag the bouncer to trigger an auth retry (in dps.)
|
||||||
|
private static final float MIN_DRAG_SIZE = 10;
|
||||||
|
|
||||||
private KeyguardSecurityModel mSecurityModel;
|
private KeyguardSecurityModel mSecurityModel;
|
||||||
private LockPatternUtils mLockPatternUtils;
|
private LockPatternUtils mLockPatternUtils;
|
||||||
|
|
||||||
@@ -70,10 +81,18 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
private SecurityCallback mSecurityCallback;
|
private SecurityCallback mSecurityCallback;
|
||||||
private AlertDialog mAlertDialog;
|
private AlertDialog mAlertDialog;
|
||||||
private InjectionInflationController mInjectionInflationController;
|
private InjectionInflationController mInjectionInflationController;
|
||||||
|
private boolean mSwipeUpToRetry;
|
||||||
|
|
||||||
|
private final ViewConfiguration mViewConfiguration;
|
||||||
|
private final SpringAnimation mSpringAnimation;
|
||||||
|
private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
|
||||||
private final KeyguardUpdateMonitor mUpdateMonitor;
|
private final KeyguardUpdateMonitor mUpdateMonitor;
|
||||||
|
|
||||||
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
|
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
|
||||||
|
private float mLastTouchY = -1;
|
||||||
|
private int mActivePointerId = -1;
|
||||||
|
private boolean mIsDragging;
|
||||||
|
private float mStartTouchY = -1;
|
||||||
|
|
||||||
// Used to notify the container when something interesting happens.
|
// Used to notify the container when something interesting happens.
|
||||||
public interface SecurityCallback {
|
public interface SecurityCallback {
|
||||||
@@ -104,9 +123,10 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
mSecurityModel = new KeyguardSecurityModel(context);
|
mSecurityModel = new KeyguardSecurityModel(context);
|
||||||
mLockPatternUtils = new LockPatternUtils(context);
|
mLockPatternUtils = new LockPatternUtils(context);
|
||||||
mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
|
mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
|
||||||
|
mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
|
||||||
mInjectionInflationController = new InjectionInflationController(
|
mInjectionInflationController = new InjectionInflationController(
|
||||||
SystemUIFactory.getInstance().getRootComponent());
|
SystemUIFactory.getInstance().getRootComponent());
|
||||||
|
mViewConfiguration = ViewConfiguration.get(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSecurityCallback(SecurityCallback callback) {
|
public void setSecurityCallback(SecurityCallback callback) {
|
||||||
@@ -118,6 +138,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||||
getSecurityView(mCurrentSecuritySelection).onResume(reason);
|
getSecurityView(mCurrentSecuritySelection).onResume(reason);
|
||||||
}
|
}
|
||||||
|
updateBiometricRetry();
|
||||||
|
updatePaddings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -131,6 +153,95 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldDelayChildPressedState() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||||
|
switch (event.getActionMasked()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
int pointerIndex = event.getActionIndex();
|
||||||
|
mStartTouchY = event.getY(pointerIndex);
|
||||||
|
mActivePointerId = event.getPointerId(pointerIndex);
|
||||||
|
mVelocityTracker.clear();
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
if (mIsDragging) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!mSwipeUpToRetry) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Avoid dragging the pattern view
|
||||||
|
if (mCurrentSecurityView.disallowInterceptTouch(event)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int index = event.findPointerIndex(mActivePointerId);
|
||||||
|
int touchSlop = mViewConfiguration.getScaledTouchSlop();
|
||||||
|
if (mCurrentSecurityView != null
|
||||||
|
&& mStartTouchY - event.getY(index) > touchSlop) {
|
||||||
|
mIsDragging = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
mIsDragging = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
|
final int action = event.getActionMasked();
|
||||||
|
switch (action) {
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
mVelocityTracker.addMovement(event);
|
||||||
|
int pointerIndex = event.findPointerIndex(mActivePointerId);
|
||||||
|
float y = event.getY(pointerIndex);
|
||||||
|
if (mLastTouchY != -1) {
|
||||||
|
float dy = y - mLastTouchY;
|
||||||
|
setTranslationY(getTranslationY() + dy * TOUCH_Y_MULTIPLIER);
|
||||||
|
}
|
||||||
|
mLastTouchY = y;
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
mActivePointerId = -1;
|
||||||
|
mLastTouchY = -1;
|
||||||
|
mIsDragging = false;
|
||||||
|
startSpringAnimation(mVelocityTracker.getYVelocity());
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_POINTER_UP:
|
||||||
|
int index = event.getActionIndex();
|
||||||
|
int pointerId = event.getPointerId(index);
|
||||||
|
if (pointerId == mActivePointerId) {
|
||||||
|
// This was our active pointer going up. Choose a new
|
||||||
|
// active pointer and adjust accordingly.
|
||||||
|
final int newPointerIndex = index == 0 ? 1 : 0;
|
||||||
|
mLastTouchY = event.getY(newPointerIndex);
|
||||||
|
mActivePointerId = event.getPointerId(newPointerIndex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (action == MotionEvent.ACTION_UP) {
|
||||||
|
if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||||
|
MIN_DRAG_SIZE, getResources().getDisplayMetrics())) {
|
||||||
|
mUpdateMonitor.requestFaceAuth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startSpringAnimation(float startVelocity) {
|
||||||
|
mSpringAnimation
|
||||||
|
.setStartVelocity(startVelocity)
|
||||||
|
.animateToFinalPosition(0);
|
||||||
|
}
|
||||||
|
|
||||||
public void startAppearAnimation() {
|
public void startAppearAnimation() {
|
||||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||||
getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
|
getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
|
||||||
@@ -145,6 +256,18 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables/disables swipe up to retry on the bouncer.
|
||||||
|
*/
|
||||||
|
private void updateBiometricRetry() {
|
||||||
|
SecurityMode securityMode = getSecurityMode();
|
||||||
|
int userId = KeyguardUpdateMonitor.getCurrentUser();
|
||||||
|
mSwipeUpToRetry = mUpdateMonitor.isUnlockWithFacePossible(userId)
|
||||||
|
&& securityMode != SecurityMode.SimPin
|
||||||
|
&& securityMode != SecurityMode.SimPuk
|
||||||
|
&& securityMode != SecurityMode.None;
|
||||||
|
}
|
||||||
|
|
||||||
public CharSequence getTitle() {
|
public CharSequence getTitle() {
|
||||||
return mSecurityViewFlipper.getTitle();
|
return mSecurityViewFlipper.getTitle();
|
||||||
}
|
}
|
||||||
@@ -195,6 +318,20 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
|
mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow();
|
||||||
|
updatePaddings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePaddings() {
|
||||||
|
int bottomPadding = getRootWindowInsets().getSystemWindowInsets().bottom;
|
||||||
|
if (getPaddingBottom() == bottomPadding) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), bottomPadding);
|
||||||
|
}
|
||||||
|
|
||||||
private void showDialog(String title, String message) {
|
private void showDialog(String title, String message) {
|
||||||
if (mAlertDialog != null) {
|
if (mAlertDialog != null) {
|
||||||
mAlertDialog.dismiss();
|
mAlertDialog.dismiss();
|
||||||
@@ -467,7 +604,6 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
|
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
|
||||||
KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
|
|
||||||
if (success) {
|
if (success) {
|
||||||
StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
|
StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
|
||||||
StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
|
StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package com.android.keyguard;
|
package com.android.keyguard;
|
||||||
|
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
import com.android.internal.widget.LockPatternUtils;
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
|
|
||||||
@@ -137,4 +138,14 @@ public interface KeyguardSecurityView {
|
|||||||
* @return The View's title.
|
* @return The View's title.
|
||||||
*/
|
*/
|
||||||
CharSequence getTitle();
|
CharSequence getTitle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the parent should not be allowed to intercept touch events.
|
||||||
|
* @param event A touch event.
|
||||||
|
* @return {@code true} if touch should be passed forward.
|
||||||
|
* @see android.view.ViewGroup#requestDisallowInterceptTouchEvent(boolean)
|
||||||
|
*/
|
||||||
|
default boolean disallowInterceptTouch(MotionEvent event) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1686,7 +1686,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
|
|||||||
&& mFpm.getEnrolledFingerprints(userId).size() > 0;
|
&& mFpm.getEnrolledFingerprints(userId).size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isUnlockWithFacePossible(int userId) {
|
/**
|
||||||
|
* If face hardware is available and user has enrolled. Not considering encryption or
|
||||||
|
* lockdown state.
|
||||||
|
*/
|
||||||
|
public boolean isUnlockWithFacePossible(int userId) {
|
||||||
return mFaceManager != null && mFaceManager.isHardwareDetected()
|
return mFaceManager != null && mFaceManager.isHardwareDetected()
|
||||||
&& !isFaceDisabled(userId)
|
&& !isFaceDisabled(userId)
|
||||||
&& mFaceManager.hasEnrolledTemplates(userId);
|
&& mFaceManager.hasEnrolledTemplates(userId);
|
||||||
@@ -2273,6 +2277,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
|
|||||||
return isSimPinSecure();
|
return isSimPinSecure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If any SIM cards are currently secure.
|
||||||
|
* @see #isSimPinSecure(State)
|
||||||
|
*/
|
||||||
public boolean isSimPinSecure() {
|
public boolean isSimPinSecure() {
|
||||||
// True if any SIM is pin secure
|
// True if any SIM is pin secure
|
||||||
for (SubscriptionInfo info : getSubscriptionInfo(false /* forceReload */)) {
|
for (SubscriptionInfo info : getSubscriptionInfo(false /* forceReload */)) {
|
||||||
@@ -2338,11 +2346,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the {@code state} is currently requiring a SIM PIN, PUK, or is disabled.
|
||||||
|
*/
|
||||||
public static boolean isSimPinSecure(IccCardConstants.State state) {
|
public static boolean isSimPinSecure(IccCardConstants.State state) {
|
||||||
final IccCardConstants.State simState = state;
|
return (state == IccCardConstants.State.PIN_REQUIRED
|
||||||
return (simState == IccCardConstants.State.PIN_REQUIRED
|
|| state == IccCardConstants.State.PUK_REQUIRED
|
||||||
|| simState == IccCardConstants.State.PUK_REQUIRED
|
|| state == IccCardConstants.State.PERM_DISABLED);
|
||||||
|| simState == IccCardConstants.State.PERM_DISABLED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisplayClientState getCachedDisplayClientState() {
|
public DisplayClientState getCachedDisplayClientState() {
|
||||||
|
|||||||
Reference in New Issue
Block a user