Revert^2 "4/N Setup Controller fo KeyguardSecurityContainer."
0d6a9012a7
Change-Id: I881bbcdc63fcbafa8966064cccb7ce1edc710062
This commit is contained in:
@@ -33,9 +33,13 @@ import android.view.SurfaceView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.keyguard.dagger.KeyguardBouncerScope;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Encapsulates all logic for secondary lockscreen state management.
|
||||
*/
|
||||
@@ -142,9 +146,9 @@ public class AdminSecondaryLockScreenController {
|
||||
}
|
||||
};
|
||||
|
||||
public AdminSecondaryLockScreenController(Context context, ViewGroup parent,
|
||||
private AdminSecondaryLockScreenController(Context context, KeyguardSecurityContainer parent,
|
||||
KeyguardUpdateMonitor updateMonitor, KeyguardSecurityCallback callback,
|
||||
Handler handler) {
|
||||
@Main Handler handler) {
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
mParent = parent;
|
||||
@@ -234,4 +238,26 @@ public class AdminSecondaryLockScreenController {
|
||||
getHolder().removeCallback(mSurfaceHolderCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@KeyguardBouncerScope
|
||||
public static class Factory {
|
||||
private final Context mContext;
|
||||
private final KeyguardSecurityContainer mParent;
|
||||
private final KeyguardUpdateMonitor mUpdateMonitor;
|
||||
private final Handler mHandler;
|
||||
|
||||
@Inject
|
||||
public Factory(Context context, KeyguardSecurityContainer parent,
|
||||
KeyguardUpdateMonitor updateMonitor, @Main Handler handler) {
|
||||
mContext = context;
|
||||
mParent = parent;
|
||||
mUpdateMonitor = updateMonitor;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
public AdminSecondaryLockScreenController create(KeyguardSecurityCallback callback) {
|
||||
return new AdminSecondaryLockScreenController(mContext, mParent, mUpdateMonitor,
|
||||
callback, mHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import android.util.AttributeSet;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.internal.util.LatencyTracker;
|
||||
import com.android.internal.widget.LockPatternChecker;
|
||||
@@ -40,8 +39,8 @@ import com.android.systemui.R;
|
||||
/**
|
||||
* Base class for PIN and password unlock screens.
|
||||
*/
|
||||
public abstract class KeyguardAbsKeyInputView extends LinearLayout
|
||||
implements KeyguardSecurityView, EmergencyButton.EmergencyButtonCallback {
|
||||
public abstract class KeyguardAbsKeyInputView extends KeyguardInputView
|
||||
implements EmergencyButton.EmergencyButtonCallback {
|
||||
protected KeyguardSecurityCallback mCallback;
|
||||
protected LockPatternUtils mLockPatternUtils;
|
||||
protected AsyncTask<?, ?, ?> mPendingLockCheck;
|
||||
|
||||
@@ -336,7 +336,7 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
|
||||
}
|
||||
|
||||
public SecurityMode getCurrentSecurityMode() {
|
||||
return mKeyguardSecurityContainerController.getCurrentSecurityMode();
|
||||
return mKeyguardSecurityContainerController.getCurrentSecuritySelection();
|
||||
}
|
||||
|
||||
public int getTop() {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A Base class for all Keyguard password/pattern/pin related inputs.
|
||||
*/
|
||||
public abstract class KeyguardInputView extends LinearLayout implements KeyguardSecurityView {
|
||||
|
||||
public KeyguardInputView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public KeyguardInputView(Context context,
|
||||
@Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public KeyguardInputView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.content.res.ColorStateList;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||
import com.android.systemui.util.ViewController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
||||
/** Controller for a {@link KeyguardSecurityView}. */
|
||||
public class KeyguardInputViewController extends ViewController<KeyguardInputView>
|
||||
implements KeyguardSecurityView {
|
||||
|
||||
private final SecurityMode mSecurityMode;
|
||||
private final LockPatternUtils mLockPatternUtils;
|
||||
|
||||
private KeyguardInputViewController(KeyguardInputView view, SecurityMode securityMode,
|
||||
LockPatternUtils lockPatternUtils,
|
||||
KeyguardSecurityCallback keyguardSecurityCallback) {
|
||||
super(view);
|
||||
mSecurityMode = securityMode;
|
||||
mLockPatternUtils = lockPatternUtils;
|
||||
mView.setKeyguardCallback(keyguardSecurityCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
mView.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewAttached() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewDetached() {
|
||||
}
|
||||
|
||||
SecurityMode getSecurityMode() {
|
||||
return mSecurityMode;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setKeyguardCallback(KeyguardSecurityCallback callback) {
|
||||
mView.setKeyguardCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLockPatternUtils(LockPatternUtils utils) {
|
||||
mView.setLockPatternUtils(utils);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
mView.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
mView.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(int reason) {
|
||||
mView.onResume(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsInput() {
|
||||
return mView.needsInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyguardSecurityCallback getCallback() {
|
||||
return mView.getCallback();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPromptReason(int reason) {
|
||||
mView.showPromptReason(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage(CharSequence message, ColorStateList colorState) {
|
||||
mView.showMessage(message, colorState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showUsabilityHint() {
|
||||
mView.showUsabilityHint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAppearAnimation() {
|
||||
mView.startAppearAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startDisappearAnimation(Runnable finishRunnable) {
|
||||
return mView.startDisappearAnimation(finishRunnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mView.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean disallowInterceptTouch(MotionEvent event) {
|
||||
return mView.disallowInterceptTouch(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartingToHide() {
|
||||
mView.onStartingToHide();
|
||||
}
|
||||
|
||||
public void showSelf() {
|
||||
KeyguardSecurityViewFlipper flipper = (KeyguardSecurityViewFlipper) mView.getParent();
|
||||
flipper.setDisplayedChild(flipper.indexOfChild(mView));
|
||||
}
|
||||
|
||||
/** Factory for a {@link KeyguardInputViewController}. */
|
||||
public static class Factory {
|
||||
private final LockPatternUtils mLockPatternUtils;
|
||||
|
||||
@Inject
|
||||
public Factory(LockPatternUtils lockPatternUtils) {
|
||||
mLockPatternUtils = lockPatternUtils;
|
||||
}
|
||||
|
||||
/** Create a new {@link KeyguardInputViewController}. */
|
||||
public KeyguardInputViewController create(KeyguardInputView keyguardInputView,
|
||||
SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback) {
|
||||
return new KeyguardInputViewController(keyguardInputView, securityMode,
|
||||
mLockPatternUtils, keyguardSecurityCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.LatencyTracker;
|
||||
@@ -48,8 +47,8 @@ import com.android.systemui.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView,
|
||||
AppearAnimationCreator<LockPatternView.CellState>,
|
||||
public class KeyguardPatternView extends KeyguardInputView
|
||||
implements AppearAnimationCreator<LockPatternView.CellState>,
|
||||
EmergencyButton.EmergencyButtonCallback {
|
||||
|
||||
private static final String TAG = "SecurityPatternView";
|
||||
|
||||
@@ -19,8 +19,6 @@ import static android.view.WindowInsets.Type.ime;
|
||||
import static android.view.WindowInsets.Type.systemBars;
|
||||
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
|
||||
|
||||
import static com.android.systemui.DejankUtils.whitelistIpcs;
|
||||
|
||||
import static java.lang.Integer.max;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -28,25 +26,14 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.metrics.LogMaker;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.UserHandle;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowInsetsAnimation;
|
||||
@@ -61,42 +48,30 @@ 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.UiEvent;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.logging.UiEventLoggerImpl;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.Interpolators;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SystemUIFactory;
|
||||
import com.android.systemui.shared.system.SysUiStatsLog;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.InjectionInflationController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
|
||||
private static final boolean DEBUG = KeyguardConstants.DEBUG;
|
||||
private static final String TAG = "KeyguardSecurityView";
|
||||
|
||||
private static final int USER_TYPE_PRIMARY = 1;
|
||||
private static final int USER_TYPE_WORK_PROFILE = 2;
|
||||
private static final int USER_TYPE_SECONDARY_USER = 3;
|
||||
public class KeyguardSecurityContainer extends FrameLayout {
|
||||
static final int USER_TYPE_PRIMARY = 1;
|
||||
static final int USER_TYPE_WORK_PROFILE = 2;
|
||||
static final int USER_TYPE_SECONDARY_USER = 3;
|
||||
|
||||
// Bouncer is dismissed due to no security.
|
||||
private static final int BOUNCER_DISMISS_NONE_SECURITY = 0;
|
||||
static final int BOUNCER_DISMISS_NONE_SECURITY = 0;
|
||||
// Bouncer is dismissed due to pin, password or pattern entered.
|
||||
private static final int BOUNCER_DISMISS_PASSWORD = 1;
|
||||
static final int BOUNCER_DISMISS_PASSWORD = 1;
|
||||
// Bouncer is dismissed due to biometric (face, fingerprint or iris) authenticated.
|
||||
private static final int BOUNCER_DISMISS_BIOMETRIC = 2;
|
||||
static final int BOUNCER_DISMISS_BIOMETRIC = 2;
|
||||
// Bouncer is dismissed due to extended access granted.
|
||||
private static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3;
|
||||
static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3;
|
||||
// Bouncer is dismissed due to sim card unlock code entered.
|
||||
private static final int BOUNCER_DISMISS_SIM = 4;
|
||||
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;
|
||||
@@ -105,36 +80,23 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
// How much to scale the default slop by, to avoid accidental drags.
|
||||
private static final float SLOP_SCALE = 4f;
|
||||
|
||||
private static final UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
|
||||
|
||||
private static final long IME_DISAPPEAR_DURATION_MS = 125;
|
||||
|
||||
private KeyguardSecurityModel mSecurityModel;
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
|
||||
@VisibleForTesting
|
||||
KeyguardSecurityViewFlipper mSecurityViewFlipper;
|
||||
private boolean mIsVerifyUnlockOnly;
|
||||
private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
|
||||
private KeyguardSecurityView mCurrentSecurityView;
|
||||
private SecurityCallback mSecurityCallback;
|
||||
private AlertDialog mAlertDialog;
|
||||
private InjectionInflationController mInjectionInflationController;
|
||||
private boolean mSwipeUpToRetry;
|
||||
private AdminSecondaryLockScreenController mSecondaryLockScreenController;
|
||||
|
||||
private final ViewConfiguration mViewConfiguration;
|
||||
private final SpringAnimation mSpringAnimation;
|
||||
private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
|
||||
private final KeyguardUpdateMonitor mUpdateMonitor;
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
|
||||
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
|
||||
private float mLastTouchY = -1;
|
||||
private int mActivePointerId = -1;
|
||||
private boolean mIsDragging;
|
||||
private float mStartTouchY = -1;
|
||||
private boolean mDisappearAnimRunning;
|
||||
private SwipeListener mSwipeListener;
|
||||
|
||||
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
|
||||
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
|
||||
@@ -184,21 +146,28 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
}
|
||||
};
|
||||
|
||||
KeyguardSecurityViewFlipper getSecurityViewFlipper() {
|
||||
return mSecurityViewFlipper;
|
||||
}
|
||||
|
||||
// Used to notify the container when something interesting happens.
|
||||
public interface SecurityCallback {
|
||||
public boolean dismiss(boolean authenticated, int targetUserId,
|
||||
boolean bypassSecondaryLockScreen);
|
||||
public void userActivity();
|
||||
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
|
||||
boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen);
|
||||
void userActivity();
|
||||
void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
|
||||
|
||||
/**
|
||||
* @param strongAuth wheher the user has authenticated with strong authentication like
|
||||
* pattern, password or PIN but not by trust agents or fingerprint
|
||||
* @param targetUserId a user that needs to be the foreground user at the finish completion.
|
||||
*/
|
||||
public void finish(boolean strongAuth, int targetUserId);
|
||||
public void reset();
|
||||
public void onCancelClicked();
|
||||
void finish(boolean strongAuth, int targetUserId);
|
||||
void reset();
|
||||
void onCancelClicked();
|
||||
}
|
||||
|
||||
public interface SwipeListener {
|
||||
void onSwipeUp();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -249,51 +218,23 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
|
||||
public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mSecurityModel = Dependency.get(KeyguardSecurityModel.class);
|
||||
mLockPatternUtils = new LockPatternUtils(context);
|
||||
mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
|
||||
mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
|
||||
mInjectionInflationController = new InjectionInflationController(
|
||||
SystemUIFactory.getInstance().getSysUIComponent().createViewInstanceCreatorFactory());
|
||||
mViewConfiguration = ViewConfiguration.get(context);
|
||||
mKeyguardStateController = Dependency.get(KeyguardStateController.class);
|
||||
mSecondaryLockScreenController = new AdminSecondaryLockScreenController(context, this,
|
||||
mUpdateMonitor, mCallback, new Handler(Looper.myLooper()));
|
||||
}
|
||||
|
||||
public void setSecurityCallback(SecurityCallback callback) {
|
||||
mSecurityCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(int reason) {
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
getSecurityView(mCurrentSecuritySelection).onResume(reason);
|
||||
}
|
||||
void onResume(SecurityMode securityMode, boolean faceAuthEnabled) {
|
||||
mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
|
||||
updateBiometricRetry();
|
||||
updateBiometricRetry(securityMode, faceAuthEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (mAlertDialog != null) {
|
||||
mAlertDialog.dismiss();
|
||||
mAlertDialog = null;
|
||||
}
|
||||
mSecondaryLockScreenController.hide();
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
getSecurityView(mCurrentSecuritySelection).onPause();
|
||||
}
|
||||
mSecurityViewFlipper.setWindowInsetsAnimationCallback(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartingToHide() {
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
getSecurityView(mCurrentSecuritySelection).onStartingToHide();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDelayChildPressedState() {
|
||||
return true;
|
||||
@@ -316,13 +257,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
return false;
|
||||
}
|
||||
// Avoid dragging the pattern view
|
||||
if (mCurrentSecurityView.disallowInterceptTouch(event)) {
|
||||
if (mSecurityViewFlipper.getSecurityView().disallowInterceptTouch(event)) {
|
||||
return false;
|
||||
}
|
||||
int index = event.findPointerIndex(mActivePointerId);
|
||||
float touchSlop = mViewConfiguration.getScaledTouchSlop() * SLOP_SCALE;
|
||||
if (mCurrentSecurityView != null && index != -1
|
||||
&& mStartTouchY - event.getY(index) > touchSlop) {
|
||||
if (index != -1 && mStartTouchY - event.getY(index) > touchSlop) {
|
||||
mIsDragging = true;
|
||||
return true;
|
||||
}
|
||||
@@ -370,31 +310,28 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
}
|
||||
if (action == MotionEvent.ACTION_UP) {
|
||||
if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||
MIN_DRAG_SIZE, getResources().getDisplayMetrics())
|
||||
&& !mUpdateMonitor.isFaceDetectionRunning()) {
|
||||
mUpdateMonitor.requestFaceAuth();
|
||||
mCallback.userActivity();
|
||||
showMessage(null, null);
|
||||
MIN_DRAG_SIZE, getResources().getDisplayMetrics())) {
|
||||
if (mSwipeListener != null) {
|
||||
mSwipeListener.onSwipeUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void setSwipeListener(SwipeListener swipeListener) {
|
||||
mSwipeListener = swipeListener;
|
||||
}
|
||||
|
||||
private void startSpringAnimation(float startVelocity) {
|
||||
mSpringAnimation
|
||||
.setStartVelocity(startVelocity)
|
||||
.animateToFinalPosition(0);
|
||||
}
|
||||
|
||||
public void startAppearAnimation() {
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
|
||||
public void startDisappearAnimation(SecurityMode securitySelection) {
|
||||
mDisappearAnimRunning = true;
|
||||
if (mCurrentSecuritySelection == SecurityMode.Password) {
|
||||
if (securitySelection == SecurityMode.Password) {
|
||||
mSecurityViewFlipper.getWindowInsetsController().controlWindowInsetsAnimation(ime(),
|
||||
IME_DISAPPEAR_DURATION_MS,
|
||||
Interpolators.LINEAR, null, new WindowInsetsAnimationControlListener() {
|
||||
@@ -439,19 +376,13 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
}
|
||||
});
|
||||
}
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation(
|
||||
onFinishRunnable);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables swipe up to retry on the bouncer.
|
||||
*/
|
||||
private void updateBiometricRetry() {
|
||||
SecurityMode securityMode = getSecurityMode();
|
||||
mSwipeUpToRetry = mKeyguardStateController.isFaceAuthEnabled()
|
||||
private void updateBiometricRetry(SecurityMode securityMode, boolean faceAuthEnabled) {
|
||||
mSwipeUpToRetry = faceAuthEnabled
|
||||
&& securityMode != SecurityMode.SimPin
|
||||
&& securityMode != SecurityMode.SimPuk
|
||||
&& securityMode != SecurityMode.None;
|
||||
@@ -461,53 +392,15 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
return mSecurityViewFlipper.getTitle();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
|
||||
final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
|
||||
KeyguardSecurityView view = null;
|
||||
final int children = mSecurityViewFlipper.getChildCount();
|
||||
for (int child = 0; child < children; child++) {
|
||||
if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
|
||||
view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
|
||||
break;
|
||||
}
|
||||
}
|
||||
int layoutId = getLayoutIdFor(securityMode);
|
||||
if (view == null && layoutId != 0) {
|
||||
final LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
|
||||
View v = mInjectionInflationController.injectable(inflater)
|
||||
.inflate(layoutId, mSecurityViewFlipper, false);
|
||||
mSecurityViewFlipper.addView(v);
|
||||
updateSecurityView(v);
|
||||
view = (KeyguardSecurityView)v;
|
||||
view.reset();
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void updateSecurityView(View view) {
|
||||
if (view instanceof KeyguardSecurityView) {
|
||||
KeyguardSecurityView ksv = (KeyguardSecurityView) view;
|
||||
ksv.setKeyguardCallback(mCallback);
|
||||
ksv.setLockPatternUtils(mLockPatternUtils);
|
||||
} else {
|
||||
Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mSecurityViewFlipper = findViewById(R.id.view_flipper);
|
||||
mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
|
||||
}
|
||||
|
||||
public void setLockPatternUtils(LockPatternUtils utils) {
|
||||
mLockPatternUtils = utils;
|
||||
mSecurityModel.setLockPatternUtils(utils);
|
||||
mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
|
||||
mSecurityViewFlipper.setLockPatternUtils(utils);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -539,11 +432,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
mAlertDialog.show();
|
||||
}
|
||||
|
||||
private void showTimeoutDialog(int userId, int timeoutMs) {
|
||||
int timeoutInSeconds = (int) timeoutMs / 1000;
|
||||
void showTimeoutDialog(int userId, int timeoutMs, LockPatternUtils lockPatternUtils,
|
||||
SecurityMode securityMode) {
|
||||
int timeoutInSeconds = timeoutMs / 1000;
|
||||
int messageId = 0;
|
||||
|
||||
switch (mSecurityModel.getSecurityMode(userId)) {
|
||||
switch (securityMode) {
|
||||
case Pattern:
|
||||
messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
|
||||
break;
|
||||
@@ -563,13 +457,13 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
|
||||
if (messageId != 0) {
|
||||
final String message = mContext.getString(messageId,
|
||||
mLockPatternUtils.getCurrentFailedPasswordAttempts(userId),
|
||||
lockPatternUtils.getCurrentFailedPasswordAttempts(userId),
|
||||
timeoutInSeconds);
|
||||
showDialog(null, message);
|
||||
}
|
||||
}
|
||||
|
||||
private void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
|
||||
void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
|
||||
String message = null;
|
||||
switch (userType) {
|
||||
case USER_TYPE_PRIMARY:
|
||||
@@ -588,7 +482,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
showDialog(null, message);
|
||||
}
|
||||
|
||||
private void showWipeDialog(int attempts, int userType) {
|
||||
void showWipeDialog(int attempts, int userType) {
|
||||
String message = null;
|
||||
switch (userType) {
|
||||
case USER_TYPE_PRIMARY:
|
||||
@@ -607,356 +501,19 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
||||
showDialog(null, message);
|
||||
}
|
||||
|
||||
private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
|
||||
// +1 for this time
|
||||
final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
|
||||
|
||||
if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
|
||||
|
||||
final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
|
||||
final int failedAttemptsBeforeWipe =
|
||||
dpm.getMaximumFailedPasswordsForWipe(null, userId);
|
||||
|
||||
final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
|
||||
(failedAttemptsBeforeWipe - failedAttempts)
|
||||
: Integer.MAX_VALUE; // because DPM returns 0 if no restriction
|
||||
if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
|
||||
// The user has installed a DevicePolicyManager that requests a user/profile to be wiped
|
||||
// N attempts. Once we get below the grace period, we post this dialog every time as a
|
||||
// clear warning until the deletion fires.
|
||||
// Check which profile has the strictest policy for failed password attempts
|
||||
final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
|
||||
int userType = USER_TYPE_PRIMARY;
|
||||
if (expiringUser == userId) {
|
||||
// TODO: http://b/23522538
|
||||
if (expiringUser != UserHandle.USER_SYSTEM) {
|
||||
userType = USER_TYPE_SECONDARY_USER;
|
||||
}
|
||||
} else if (expiringUser != UserHandle.USER_NULL) {
|
||||
userType = USER_TYPE_WORK_PROFILE;
|
||||
} // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
|
||||
if (remainingBeforeWipe > 0) {
|
||||
showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
|
||||
} else {
|
||||
// Too many attempts. The device will be wiped shortly.
|
||||
Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
|
||||
showWipeDialog(failedAttempts, userType);
|
||||
}
|
||||
}
|
||||
mLockPatternUtils.reportFailedPasswordAttempt(userId);
|
||||
if (timeoutMs > 0) {
|
||||
mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
|
||||
showTimeoutDialog(userId, timeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the primary security screen for the user. This will be either the multi-selector
|
||||
* or the user's security method.
|
||||
* @param turningOff true if the device is being turned off
|
||||
*/
|
||||
void showPrimarySecurityScreen(boolean turningOff) {
|
||||
SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
|
||||
KeyguardUpdateMonitor.getCurrentUser()));
|
||||
if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
|
||||
showSecurityScreen(securityMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the next security screen if there is one.
|
||||
* @param authenticated true if the user entered the correct authentication
|
||||
* @param targetUserId a user that needs to be the foreground user at the finish (if called)
|
||||
* completion.
|
||||
* @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
|
||||
* secondary lock screen requirement, if any.
|
||||
* @return true if keyguard is done
|
||||
*/
|
||||
boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
|
||||
boolean bypassSecondaryLockScreen) {
|
||||
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
|
||||
boolean finish = false;
|
||||
boolean strongAuth = false;
|
||||
int eventSubtype = -1;
|
||||
BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
|
||||
if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
|
||||
finish = true;
|
||||
eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
|
||||
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS;
|
||||
} else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
|
||||
finish = true;
|
||||
eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
|
||||
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_BIOMETRIC;
|
||||
} else if (SecurityMode.None == mCurrentSecuritySelection) {
|
||||
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
|
||||
if (SecurityMode.None == securityMode) {
|
||||
finish = true; // no security required
|
||||
eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
|
||||
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY;
|
||||
} else {
|
||||
showSecurityScreen(securityMode); // switch to the alternate security view
|
||||
}
|
||||
} else if (authenticated) {
|
||||
switch (mCurrentSecuritySelection) {
|
||||
case Pattern:
|
||||
case Password:
|
||||
case PIN:
|
||||
strongAuth = true;
|
||||
finish = true;
|
||||
eventSubtype = BOUNCER_DISMISS_PASSWORD;
|
||||
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
|
||||
break;
|
||||
|
||||
case SimPin:
|
||||
case SimPuk:
|
||||
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
|
||||
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
|
||||
if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
|
||||
KeyguardUpdateMonitor.getCurrentUser())) {
|
||||
finish = true;
|
||||
eventSubtype = BOUNCER_DISMISS_SIM;
|
||||
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
|
||||
} else {
|
||||
showSecurityScreen(securityMode);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
|
||||
showPrimarySecurityScreen(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check for device admin specified additional security measures.
|
||||
if (finish && !bypassSecondaryLockScreen) {
|
||||
Intent secondaryLockscreenIntent =
|
||||
mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
|
||||
if (secondaryLockscreenIntent != null) {
|
||||
mSecondaryLockScreenController.show(secondaryLockscreenIntent);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (eventSubtype != -1) {
|
||||
mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
|
||||
.setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
|
||||
}
|
||||
if (uiEvent != BouncerUiEvent.UNKNOWN) {
|
||||
sUiEventLogger.log(uiEvent);
|
||||
}
|
||||
if (finish) {
|
||||
mSecurityCallback.finish(strongAuth, targetUserId);
|
||||
}
|
||||
return finish;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches to the given security view unless it's already being shown, in which case
|
||||
* this is a no-op.
|
||||
*
|
||||
* @param securityMode
|
||||
*/
|
||||
private void showSecurityScreen(SecurityMode securityMode) {
|
||||
if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
|
||||
|
||||
if (securityMode == mCurrentSecuritySelection) return;
|
||||
|
||||
KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
|
||||
KeyguardSecurityView newView = getSecurityView(securityMode);
|
||||
|
||||
// Emulate Activity life cycle
|
||||
if (oldView != null) {
|
||||
oldView.onPause();
|
||||
oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
|
||||
}
|
||||
if (securityMode != SecurityMode.None) {
|
||||
newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
|
||||
newView.setKeyguardCallback(mCallback);
|
||||
}
|
||||
|
||||
// Find and show this child.
|
||||
final int childCount = mSecurityViewFlipper.getChildCount();
|
||||
|
||||
final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
|
||||
mSecurityViewFlipper.setDisplayedChild(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mCurrentSecuritySelection = securityMode;
|
||||
mCurrentSecurityView = newView;
|
||||
mSecurityCallback.onSecurityModeChanged(securityMode,
|
||||
securityMode != SecurityMode.None && newView.needsInput());
|
||||
}
|
||||
|
||||
private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
|
||||
public void userActivity() {
|
||||
if (mSecurityCallback != null) {
|
||||
mSecurityCallback.userActivity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserInput() {
|
||||
mUpdateMonitor.cancelFaceAuth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss(boolean authenticated, int targetId) {
|
||||
dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss(boolean authenticated, int targetId,
|
||||
boolean bypassSecondaryLockScreen) {
|
||||
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
|
||||
}
|
||||
|
||||
public boolean isVerifyUnlockOnly() {
|
||||
return mIsVerifyUnlockOnly;
|
||||
}
|
||||
|
||||
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
|
||||
if (success) {
|
||||
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
|
||||
SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
|
||||
mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
|
||||
// Force a garbage collection in an attempt to erase any lockscreen password left in
|
||||
// memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard
|
||||
// dismiss animation janky.
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException ignored) { }
|
||||
Runtime.getRuntime().gc();
|
||||
});
|
||||
} else {
|
||||
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
|
||||
SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
|
||||
KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs);
|
||||
}
|
||||
mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
|
||||
.setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
|
||||
sUiEventLogger.log(success ? BouncerUiEvent.BOUNCER_PASSWORD_SUCCESS
|
||||
: BouncerUiEvent.BOUNCER_PASSWORD_FAILURE);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mSecurityCallback.reset();
|
||||
}
|
||||
|
||||
public void onCancelClicked() {
|
||||
mSecurityCallback.onCancelClicked();
|
||||
}
|
||||
};
|
||||
|
||||
// The following is used to ignore callbacks from SecurityViews that are no longer current
|
||||
// (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
|
||||
// state for the current security method.
|
||||
private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
|
||||
@Override
|
||||
public void userActivity() { }
|
||||
@Override
|
||||
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
|
||||
@Override
|
||||
public boolean isVerifyUnlockOnly() { return false; }
|
||||
@Override
|
||||
public void dismiss(boolean securityVerified, int targetUserId) { }
|
||||
@Override
|
||||
public void dismiss(boolean authenticated, int targetId,
|
||||
boolean bypassSecondaryLockScreen) { }
|
||||
@Override
|
||||
public void onUserInput() { }
|
||||
@Override
|
||||
public void reset() {}
|
||||
};
|
||||
|
||||
private int getSecurityViewIdForMode(SecurityMode securityMode) {
|
||||
switch (securityMode) {
|
||||
case Pattern: return R.id.keyguard_pattern_view;
|
||||
case PIN: return R.id.keyguard_pin_view;
|
||||
case Password: return R.id.keyguard_password_view;
|
||||
case SimPin: return R.id.keyguard_sim_pin_view;
|
||||
case SimPuk: return R.id.keyguard_sim_puk_view;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public int getLayoutIdFor(SecurityMode securityMode) {
|
||||
switch (securityMode) {
|
||||
case Pattern: return R.layout.keyguard_pattern_view;
|
||||
case PIN: return R.layout.keyguard_pin_view;
|
||||
case Password: return R.layout.keyguard_password_view;
|
||||
case SimPin: return R.layout.keyguard_sim_pin_view;
|
||||
case SimPuk: return R.layout.keyguard_sim_puk_view;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public SecurityMode getSecurityMode() {
|
||||
return mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser());
|
||||
}
|
||||
|
||||
public SecurityMode getCurrentSecurityMode() {
|
||||
return mCurrentSecuritySelection;
|
||||
}
|
||||
|
||||
public KeyguardSecurityView getCurrentSecurityView() {
|
||||
return mCurrentSecurityView;
|
||||
}
|
||||
|
||||
public void verifyUnlock() {
|
||||
mIsVerifyUnlockOnly = true;
|
||||
showSecurityScreen(getSecurityMode());
|
||||
}
|
||||
|
||||
public SecurityMode getCurrentSecuritySelection() {
|
||||
return mCurrentSecuritySelection;
|
||||
}
|
||||
|
||||
public void dismiss(boolean authenticated, int targetUserId) {
|
||||
mCallback.dismiss(authenticated, targetUserId);
|
||||
}
|
||||
|
||||
public boolean needsInput() {
|
||||
return mSecurityViewFlipper.needsInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeyguardCallback(KeyguardSecurityCallback callback) {
|
||||
mSecurityViewFlipper.setKeyguardCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
mSecurityViewFlipper.reset();
|
||||
mDisappearAnimRunning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyguardSecurityCallback getCallback() {
|
||||
return mSecurityViewFlipper.getCallback();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPromptReason(int reason) {
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
if (reason != PROMPT_REASON_NONE) {
|
||||
Log.i(TAG, "Strong auth required, reason: " + reason);
|
||||
}
|
||||
getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
|
||||
}
|
||||
}
|
||||
|
||||
public void showMessage(CharSequence message, ColorStateList colorState) {
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
getSecurityView(mCurrentSecuritySelection).showMessage(message, colorState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showUsabilityHint() {
|
||||
mSecurityViewFlipper.showUsabilityHint();
|
||||
}
|
||||
|
||||
@@ -16,33 +16,197 @@
|
||||
|
||||
package com.android.keyguard;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
|
||||
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS;
|
||||
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY;
|
||||
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_PASSWORD;
|
||||
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_SIM;
|
||||
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_PRIMARY;
|
||||
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER;
|
||||
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
|
||||
import static com.android.systemui.DejankUtils.whitelistIpcs;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.metrics.LogMaker;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent;
|
||||
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
|
||||
import com.android.keyguard.KeyguardSecurityContainer.SwipeListener;
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.shared.system.SysUiStatsLog;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.InjectionInflationController;
|
||||
import com.android.systemui.util.ViewController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** Controller for {@link KeyguardSecurityContainer} */
|
||||
public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer> {
|
||||
public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer>
|
||||
implements KeyguardSecurityView {
|
||||
|
||||
private static final boolean DEBUG = KeyguardConstants.DEBUG;
|
||||
private static final String TAG = "KeyguardSecurityView";
|
||||
|
||||
private final AdminSecondaryLockScreenController mAdminSecondaryLockScreenController;
|
||||
private final LockPatternUtils mLockPatternUtils;
|
||||
private final KeyguardSecurityViewController.Factory mKeyguardSecurityViewControllerFactory;
|
||||
private final KeyguardUpdateMonitor mUpdateMonitor;
|
||||
private final KeyguardSecurityModel mSecurityModel;
|
||||
private final MetricsLogger mMetricsLogger;
|
||||
private final UiEventLogger mUiEventLogger;
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final KeyguardInputViewController.Factory mKeyguardSecurityViewControllerFactory;
|
||||
private final List<KeyguardInputViewController> mChildren = new ArrayList<>();
|
||||
|
||||
private SecurityCallback mSecurityCallback;
|
||||
private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
|
||||
private KeyguardSecurityView mCurrentSecurityView;
|
||||
|
||||
private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
|
||||
public void userActivity() {
|
||||
if (mSecurityCallback != null) {
|
||||
mSecurityCallback.userActivity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserInput() {
|
||||
mUpdateMonitor.cancelFaceAuth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss(boolean authenticated, int targetId) {
|
||||
dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss(boolean authenticated, int targetId,
|
||||
boolean bypassSecondaryLockScreen) {
|
||||
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
|
||||
}
|
||||
|
||||
public boolean isVerifyUnlockOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
|
||||
if (success) {
|
||||
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
|
||||
SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
|
||||
mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
|
||||
// Force a garbage collection in an attempt to erase any lockscreen password left in
|
||||
// memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard
|
||||
// dismiss animation janky.
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException ignored) { }
|
||||
Runtime.getRuntime().gc();
|
||||
});
|
||||
} else {
|
||||
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
|
||||
SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
|
||||
reportFailedUnlockAttempt(userId, timeoutMs);
|
||||
}
|
||||
mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
|
||||
.setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
|
||||
mUiEventLogger.log(success ? BouncerUiEvent.BOUNCER_PASSWORD_SUCCESS
|
||||
: BouncerUiEvent.BOUNCER_PASSWORD_FAILURE);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mSecurityCallback.reset();
|
||||
}
|
||||
|
||||
public void onCancelClicked() {
|
||||
mSecurityCallback.onCancelClicked();
|
||||
}
|
||||
};
|
||||
|
||||
// The following is used to ignore callbacks from SecurityViews that are no longer current
|
||||
// (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
|
||||
// state for the current security method.
|
||||
private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
|
||||
@Override
|
||||
public void userActivity() { }
|
||||
@Override
|
||||
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
|
||||
@Override
|
||||
public boolean isVerifyUnlockOnly() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void dismiss(boolean securityVerified, int targetUserId) { }
|
||||
@Override
|
||||
public void dismiss(boolean authenticated, int targetId,
|
||||
boolean bypassSecondaryLockScreen) { }
|
||||
@Override
|
||||
public void onUserInput() { }
|
||||
@Override
|
||||
public void reset() {}
|
||||
};
|
||||
|
||||
private SwipeListener mSwipeListener = new SwipeListener() {
|
||||
@Override
|
||||
public void onSwipeUp() {
|
||||
if (!mUpdateMonitor.isFaceDetectionRunning()) {
|
||||
mUpdateMonitor.requestFaceAuth();
|
||||
mKeyguardSecurityCallback.userActivity();
|
||||
showMessage(null, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Inject
|
||||
KeyguardSecurityContainerController(KeyguardSecurityContainer view,
|
||||
AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
|
||||
LockPatternUtils lockPatternUtils,
|
||||
KeyguardSecurityViewController.Factory keyguardSecurityViewControllerFactory) {
|
||||
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
KeyguardSecurityModel keyguardSecurityModel,
|
||||
MetricsLogger metricsLogger,
|
||||
UiEventLogger uiEventLogger,
|
||||
KeyguardStateController keyguardStateController,
|
||||
LayoutInflater layoutInflater,
|
||||
InjectionInflationController injectionInflationController,
|
||||
KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory) {
|
||||
super(view);
|
||||
mLockPatternUtils = lockPatternUtils;
|
||||
mUpdateMonitor = keyguardUpdateMonitor;
|
||||
mSecurityModel = keyguardSecurityModel;
|
||||
mMetricsLogger = metricsLogger;
|
||||
mUiEventLogger = uiEventLogger;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
mLayoutInflater = injectionInflationController.injectable(layoutInflater);
|
||||
view.setLockPatternUtils(mLockPatternUtils);
|
||||
mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory;
|
||||
mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
|
||||
mKeyguardSecurityCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewAttached() {
|
||||
mView.setSwipeListener(mSwipeListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,27 +215,48 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
|
||||
/** */
|
||||
public void onPause() {
|
||||
mAdminSecondaryLockScreenController.hide();
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
getSecurityView(mCurrentSecuritySelection).onPause();
|
||||
}
|
||||
mView.onPause();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows the primary security screen for the user. This will be either the multi-selector
|
||||
* or the user's security method.
|
||||
* @param turningOff true if the device is being turned off
|
||||
*/
|
||||
public void showPrimarySecurityScreen(boolean turningOff) {
|
||||
mView.showPrimarySecurityScreen(turningOff);
|
||||
SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
|
||||
KeyguardUpdateMonitor.getCurrentUser()));
|
||||
if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
|
||||
showSecurityScreen(securityMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPromptReason(int reason) {
|
||||
mView.showPromptReason(reason);
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
if (reason != PROMPT_REASON_NONE) {
|
||||
Log.i(TAG, "Strong auth required, reason: " + reason);
|
||||
}
|
||||
getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
|
||||
}
|
||||
}
|
||||
|
||||
public void showMessage(CharSequence message, ColorStateList colorState) {
|
||||
mView.showMessage(message, colorState);
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
getSecurityView(mCurrentSecuritySelection).showMessage(message, colorState);
|
||||
}
|
||||
}
|
||||
|
||||
public SecurityMode getCurrentSecuritySelection() {
|
||||
return mView.getCurrentSecuritySelection();
|
||||
return mCurrentSecuritySelection;
|
||||
}
|
||||
|
||||
public void dismiss(boolean authenticated, int targetUserId) {
|
||||
mView.dismiss(authenticated, targetUserId);
|
||||
mKeyguardSecurityCallback.dismiss(authenticated, targetUserId);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
@@ -82,37 +267,276 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
return mView.getTitle();
|
||||
}
|
||||
|
||||
public void onResume(int screenOn) {
|
||||
mView.onResume(screenOn);
|
||||
@Override
|
||||
public void onResume(int reason) {
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
getSecurityView(mCurrentSecuritySelection).onResume(reason);
|
||||
}
|
||||
mView.onResume(
|
||||
mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()),
|
||||
mKeyguardStateController.isFaceAuthEnabled());
|
||||
}
|
||||
|
||||
public void startAppearAnimation() {
|
||||
mView.startAppearAnimation();
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
|
||||
return mView.startDisappearAnimation(onFinishRunnable);
|
||||
mView.startDisappearAnimation(getCurrentSecuritySelection());
|
||||
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation(
|
||||
onFinishRunnable);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onStartingToHide() {
|
||||
mView.onStartingToHide();
|
||||
if (mCurrentSecuritySelection != SecurityMode.None) {
|
||||
getSecurityView(mCurrentSecuritySelection).onStartingToHide();
|
||||
}
|
||||
}
|
||||
|
||||
public void setSecurityCallback(SecurityCallback securityCallback) {
|
||||
mView.setSecurityCallback(securityCallback);
|
||||
mSecurityCallback = securityCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the next security screen if there is one.
|
||||
* @param authenticated true if the user entered the correct authentication
|
||||
* @param targetUserId a user that needs to be the foreground user at the finish (if called)
|
||||
* completion.
|
||||
* @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
|
||||
* secondary lock screen requirement, if any.
|
||||
* @return true if keyguard is done
|
||||
*/
|
||||
public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
|
||||
boolean bypassSecondaryLockScreen) {
|
||||
return mView.showNextSecurityScreenOrFinish(
|
||||
authenticated, targetUserId, bypassSecondaryLockScreen);
|
||||
|
||||
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
|
||||
boolean finish = false;
|
||||
boolean strongAuth = false;
|
||||
int eventSubtype = -1;
|
||||
BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
|
||||
if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
|
||||
finish = true;
|
||||
eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
|
||||
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS;
|
||||
} else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
|
||||
finish = true;
|
||||
eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
|
||||
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_BIOMETRIC;
|
||||
} else if (SecurityMode.None == getCurrentSecuritySelection()) {
|
||||
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
|
||||
if (SecurityMode.None == securityMode) {
|
||||
finish = true; // no security required
|
||||
eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
|
||||
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY;
|
||||
} else {
|
||||
showSecurityScreen(securityMode); // switch to the alternate security view
|
||||
}
|
||||
} else if (authenticated) {
|
||||
switch (getCurrentSecuritySelection()) {
|
||||
case Pattern:
|
||||
case Password:
|
||||
case PIN:
|
||||
strongAuth = true;
|
||||
finish = true;
|
||||
eventSubtype = BOUNCER_DISMISS_PASSWORD;
|
||||
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
|
||||
break;
|
||||
|
||||
case SimPin:
|
||||
case SimPuk:
|
||||
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
|
||||
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
|
||||
if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
|
||||
KeyguardUpdateMonitor.getCurrentUser())) {
|
||||
finish = true;
|
||||
eventSubtype = BOUNCER_DISMISS_SIM;
|
||||
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
|
||||
} else {
|
||||
showSecurityScreen(securityMode);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.v(TAG, "Bad security screen " + getCurrentSecuritySelection()
|
||||
+ ", fail safe");
|
||||
showPrimarySecurityScreen(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check for device admin specified additional security measures.
|
||||
if (finish && !bypassSecondaryLockScreen) {
|
||||
Intent secondaryLockscreenIntent =
|
||||
mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
|
||||
if (secondaryLockscreenIntent != null) {
|
||||
mAdminSecondaryLockScreenController.show(secondaryLockscreenIntent);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (eventSubtype != -1) {
|
||||
mMetricsLogger.write(new LogMaker(MetricsProto.MetricsEvent.BOUNCER)
|
||||
.setType(MetricsProto.MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
|
||||
}
|
||||
if (uiEvent != BouncerUiEvent.UNKNOWN) {
|
||||
mUiEventLogger.log(uiEvent);
|
||||
}
|
||||
if (finish) {
|
||||
mSecurityCallback.finish(strongAuth, targetUserId);
|
||||
}
|
||||
return finish;
|
||||
}
|
||||
|
||||
public boolean needsInput() {
|
||||
return mView.needsInput();
|
||||
}
|
||||
|
||||
public SecurityMode getCurrentSecurityMode() {
|
||||
return mView.getCurrentSecurityMode();
|
||||
|
||||
/**
|
||||
* Switches to the given security view unless it's already being shown, in which case
|
||||
* this is a no-op.
|
||||
*
|
||||
* @param securityMode
|
||||
*/
|
||||
void showSecurityScreen(SecurityMode securityMode) {
|
||||
if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
|
||||
|
||||
if (securityMode == mCurrentSecuritySelection) return;
|
||||
|
||||
KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
|
||||
KeyguardSecurityView newView = getSecurityView(securityMode);
|
||||
|
||||
// Emulate Activity life cycle
|
||||
if (oldView != null) {
|
||||
oldView.onPause();
|
||||
oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
|
||||
}
|
||||
if (newView != null) {
|
||||
newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
|
||||
newView.setKeyguardCallback(mKeyguardSecurityCallback);
|
||||
}
|
||||
|
||||
// Find and show this child.
|
||||
for (KeyguardInputViewController child : mChildren) {
|
||||
if (child.getSecurityMode().equals(securityMode)) {
|
||||
child.showSelf();
|
||||
}
|
||||
}
|
||||
|
||||
mCurrentSecuritySelection = securityMode;
|
||||
mCurrentSecurityView = newView;
|
||||
mSecurityCallback.onSecurityModeChanged(
|
||||
securityMode, newView != null && newView.needsInput());
|
||||
}
|
||||
|
||||
public void reportFailedUnlockAttempt(int userId, int timeoutMs) {
|
||||
// +1 for this time
|
||||
final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
|
||||
|
||||
if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
|
||||
|
||||
final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
|
||||
final int failedAttemptsBeforeWipe =
|
||||
dpm.getMaximumFailedPasswordsForWipe(null, userId);
|
||||
|
||||
final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0
|
||||
? (failedAttemptsBeforeWipe - failedAttempts)
|
||||
: Integer.MAX_VALUE; // because DPM returns 0 if no restriction
|
||||
if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
|
||||
// The user has installed a DevicePolicyManager that requests a user/profile to be wiped
|
||||
// N attempts. Once we get below the grace period, we post this dialog every time as a
|
||||
// clear warning until the deletion fires.
|
||||
// Check which profile has the strictest policy for failed password attempts
|
||||
final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
|
||||
int userType = USER_TYPE_PRIMARY;
|
||||
if (expiringUser == userId) {
|
||||
// TODO: http://b/23522538
|
||||
if (expiringUser != UserHandle.USER_SYSTEM) {
|
||||
userType = USER_TYPE_SECONDARY_USER;
|
||||
}
|
||||
} else if (expiringUser != UserHandle.USER_NULL) {
|
||||
userType = USER_TYPE_WORK_PROFILE;
|
||||
} // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
|
||||
if (remainingBeforeWipe > 0) {
|
||||
mView.showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
|
||||
} else {
|
||||
// Too many attempts. The device will be wiped shortly.
|
||||
Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
|
||||
mView.showWipeDialog(failedAttempts, userType);
|
||||
}
|
||||
}
|
||||
mLockPatternUtils.reportFailedPasswordAttempt(userId);
|
||||
if (timeoutMs > 0) {
|
||||
mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
|
||||
mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils,
|
||||
mSecurityModel.getSecurityMode(userId));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeyguardCallback(KeyguardSecurityCallback callback) {
|
||||
// no-op. This should never be reset.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLockPatternUtils(LockPatternUtils utils) {
|
||||
// We already have one of these.
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyguardSecurityCallback getCallback() {
|
||||
return mView.getCallback();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showUsabilityHint() {
|
||||
mView.showUsabilityHint();
|
||||
}
|
||||
|
||||
private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
|
||||
KeyguardInputViewController childController = null;
|
||||
for (KeyguardInputViewController mChild : mChildren) {
|
||||
if (mChild.getSecurityMode() == securityMode) {
|
||||
childController = mChild;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (childController == null
|
||||
&& securityMode != SecurityMode.None && securityMode != SecurityMode.Invalid) {
|
||||
|
||||
int layoutId = getLayoutIdFor(securityMode);
|
||||
KeyguardInputView view = null;
|
||||
if (layoutId != 0) {
|
||||
if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
|
||||
view = (KeyguardInputView) mLayoutInflater.inflate(
|
||||
layoutId, mView.getSecurityViewFlipper(), false);
|
||||
mView.getSecurityViewFlipper().addView(view);
|
||||
childController = mKeyguardSecurityViewControllerFactory.create(
|
||||
view, securityMode, mKeyguardSecurityCallback);
|
||||
|
||||
mChildren.add(childController);
|
||||
}
|
||||
}
|
||||
|
||||
return childController;
|
||||
}
|
||||
|
||||
private int getLayoutIdFor(SecurityMode securityMode) {
|
||||
switch (securityMode) {
|
||||
case Pattern: return com.android.systemui.R.layout.keyguard_pattern_view;
|
||||
case PIN: return com.android.systemui.R.layout.keyguard_pin_view;
|
||||
case Password: return com.android.systemui.R.layout.keyguard_password_view;
|
||||
case SimPin: return com.android.systemui.R.layout.keyguard_sim_pin_view;
|
||||
case SimPuk: return R.layout.keyguard_sim_puk_view;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,13 +18,14 @@ package com.android.keyguard;
|
||||
import static com.android.systemui.DejankUtils.whitelistIpcs;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -33,7 +34,7 @@ public class KeyguardSecurityModel {
|
||||
|
||||
/**
|
||||
* The different types of security available.
|
||||
* @see KeyguardSecurityContainer#showSecurityScreen
|
||||
* @see KeyguardSecurityContainerController#showSecurityScreen
|
||||
*/
|
||||
public enum SecurityMode {
|
||||
Invalid, // NULL state
|
||||
@@ -45,21 +46,15 @@ public class KeyguardSecurityModel {
|
||||
SimPuk // Unlock by entering a sim puk
|
||||
}
|
||||
|
||||
private final Context mContext;
|
||||
private final boolean mIsPukScreenAvailable;
|
||||
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
private final LockPatternUtils mLockPatternUtils;
|
||||
|
||||
@Inject
|
||||
KeyguardSecurityModel(Context context) {
|
||||
mContext = context;
|
||||
mLockPatternUtils = new LockPatternUtils(context);
|
||||
mIsPukScreenAvailable = mContext.getResources().getBoolean(
|
||||
KeyguardSecurityModel(@Main Resources resources, LockPatternUtils lockPatternUtils) {
|
||||
mIsPukScreenAvailable = resources.getBoolean(
|
||||
com.android.internal.R.bool.config_enable_puk_unlock_screen);
|
||||
}
|
||||
|
||||
void setLockPatternUtils(LockPatternUtils utils) {
|
||||
mLockPatternUtils = utils;
|
||||
mLockPatternUtils = lockPatternUtils;
|
||||
}
|
||||
|
||||
public SecurityMode getSecurityMode(int userId) {
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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.view.View;
|
||||
|
||||
import com.android.systemui.util.ViewController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
||||
/** Controller for a {@link KeyguardSecurityView}. */
|
||||
public class KeyguardSecurityViewController extends ViewController<View> {
|
||||
|
||||
private final KeyguardSecurityView mView;
|
||||
|
||||
private KeyguardSecurityViewController(KeyguardSecurityView view) {
|
||||
super((View) view);
|
||||
// KeyguardSecurityView isn't actually a View, so we need to track it ourselves.
|
||||
mView = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewAttached() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewDetached() {
|
||||
|
||||
}
|
||||
|
||||
/** Factory for a {@link KeyguardSecurityViewController}. */
|
||||
public static class Factory {
|
||||
@Inject
|
||||
public Factory() {
|
||||
}
|
||||
|
||||
/** Create a new {@link KeyguardSecurityViewController}. */
|
||||
public KeyguardSecurityViewController create(KeyguardSecurityView view) {
|
||||
return new KeyguardSecurityViewController(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,6 +289,7 @@ public class DependencyProvider {
|
||||
|
||||
/** */
|
||||
@Provides
|
||||
@SysUISingleton
|
||||
public LockPatternUtils provideLockPatternUtils(Context context) {
|
||||
return new LockPatternUtils(context);
|
||||
}
|
||||
|
||||
@@ -41,8 +41,6 @@ import android.testing.TestableLooper.RunWithLooper;
|
||||
import android.testing.ViewUtils;
|
||||
import android.view.SurfaceControlViewHost;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
@@ -67,7 +65,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
||||
private ComponentName mComponentName;
|
||||
private Intent mServiceIntent;
|
||||
private TestableLooper mTestableLooper;
|
||||
private ViewGroup mParent;
|
||||
private KeyguardSecurityContainer mKeyguardSecurityContainer;
|
||||
|
||||
@Mock
|
||||
private Handler mHandler;
|
||||
@@ -84,8 +82,8 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mParent = spy(new FrameLayout(mContext));
|
||||
ViewUtils.attachView(mParent);
|
||||
mKeyguardSecurityContainer = spy(new KeyguardSecurityContainer(mContext));
|
||||
ViewUtils.attachView(mKeyguardSecurityContainer);
|
||||
|
||||
mTestableLooper = TestableLooper.get(this);
|
||||
mComponentName = new ComponentName(mContext, "FakeKeyguardClient.class");
|
||||
@@ -96,13 +94,14 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
||||
when(mKeyguardClient.queryLocalInterface(anyString())).thenReturn(mKeyguardClient);
|
||||
when(mKeyguardClient.asBinder()).thenReturn(mKeyguardClient);
|
||||
|
||||
mTestController = new AdminSecondaryLockScreenController(
|
||||
mContext, mParent, mUpdateMonitor, mKeyguardCallback, mHandler);
|
||||
mTestController = new AdminSecondaryLockScreenController.Factory(
|
||||
mContext, mKeyguardSecurityContainer, mUpdateMonitor, mHandler)
|
||||
.create(mKeyguardCallback);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ViewUtils.detachView(mParent);
|
||||
ViewUtils.detachView(mKeyguardSecurityContainer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -146,7 +145,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
||||
SurfaceView v = verifySurfaceReady();
|
||||
|
||||
mTestController.hide();
|
||||
verify(mParent).removeView(v);
|
||||
verify(mKeyguardSecurityContainer).removeView(v);
|
||||
assertThat(mContext.isBound(mComponentName)).isFalse();
|
||||
}
|
||||
|
||||
@@ -154,7 +153,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
||||
public void testHide_notShown() throws Exception {
|
||||
mTestController.hide();
|
||||
// Nothing should happen if trying to hide when the view isn't attached yet.
|
||||
verify(mParent, never()).removeView(any(SurfaceView.class));
|
||||
verify(mKeyguardSecurityContainer, never()).removeView(any(SurfaceView.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -182,7 +181,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
||||
private SurfaceView verifySurfaceReady() throws Exception {
|
||||
mTestableLooper.processAllMessages();
|
||||
ArgumentCaptor<SurfaceView> captor = ArgumentCaptor.forClass(SurfaceView.class);
|
||||
verify(mParent).addView(captor.capture());
|
||||
verify(mKeyguardSecurityContainer).addView(captor.capture());
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
verify(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
|
||||
@@ -190,7 +189,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
private void verifyViewDismissed(SurfaceView v) throws Exception {
|
||||
verify(mParent).removeView(v);
|
||||
verify(mKeyguardSecurityContainer).removeView(v);
|
||||
verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true);
|
||||
assertThat(mContext.isBound(mComponentName)).isFalse();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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 static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsetsController;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.InjectionInflationController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper()
|
||||
public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
|
||||
@Rule
|
||||
public MockitoRule mRule = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private KeyguardSecurityContainer mView;
|
||||
@Mock
|
||||
private AdminSecondaryLockScreenController.Factory mAdminSecondaryLockScreenControllerFactory;
|
||||
@Mock
|
||||
private AdminSecondaryLockScreenController mAdminSecondaryLockScreenController;
|
||||
@Mock
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
@Mock
|
||||
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
@Mock
|
||||
private KeyguardSecurityModel mKeyguardSecurityModel;
|
||||
@Mock
|
||||
private MetricsLogger mMetricsLogger;
|
||||
@Mock
|
||||
private UiEventLogger mUiEventLogger;
|
||||
@Mock
|
||||
private KeyguardStateController mKeyguardStateController;
|
||||
@Mock
|
||||
private LayoutInflater mLayoutInflater;
|
||||
@Mock
|
||||
private InjectionInflationController mInjectionInflationController;
|
||||
@Mock
|
||||
private KeyguardInputViewController.Factory mKeyguardSecurityViewControllerFactory;
|
||||
@Mock
|
||||
private KeyguardInputViewController mKeyguardInputViewController;
|
||||
@Mock
|
||||
private KeyguardInputView mInputView;
|
||||
@Mock
|
||||
private KeyguardSecurityContainer.SecurityCallback mSecurityCallback;
|
||||
@Mock
|
||||
private WindowInsetsController mWindowInsetsController;
|
||||
@Mock
|
||||
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
|
||||
|
||||
private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
|
||||
.thenReturn(mAdminSecondaryLockScreenController);
|
||||
when(mInjectionInflationController.injectable(mLayoutInflater)).thenReturn(mLayoutInflater);
|
||||
when(mKeyguardSecurityViewControllerFactory.create(
|
||||
any(KeyguardInputView.class), any(SecurityMode.class),
|
||||
any(KeyguardSecurityCallback.class)))
|
||||
.thenReturn(mKeyguardInputViewController);
|
||||
when(mView.getSecurityViewFlipper()).thenReturn(mSecurityViewFlipper);
|
||||
when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
|
||||
|
||||
mKeyguardSecurityContainerController = new KeyguardSecurityContainerController(
|
||||
mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
|
||||
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
|
||||
mKeyguardStateController, mLayoutInflater, mInjectionInflationController,
|
||||
mKeyguardSecurityViewControllerFactory
|
||||
);
|
||||
|
||||
mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showSecurityScreen_canInflateAllModes() {
|
||||
KeyguardSecurityModel.SecurityMode[] modes =
|
||||
KeyguardSecurityModel.SecurityMode.values();
|
||||
for (KeyguardSecurityModel.SecurityMode mode : modes) {
|
||||
reset(mLayoutInflater);
|
||||
when(mLayoutInflater.inflate(anyInt(), eq(mSecurityViewFlipper), eq(false)))
|
||||
.thenReturn(mInputView);
|
||||
when(mKeyguardInputViewController.getSecurityMode()).thenReturn(mode);
|
||||
mKeyguardSecurityContainerController.showSecurityScreen(mode);
|
||||
if (mode == SecurityMode.Invalid || mode == SecurityMode.None) {
|
||||
verify(mLayoutInflater, never()).inflate(
|
||||
anyInt(), any(ViewGroup.class), anyBoolean());
|
||||
} else {
|
||||
verify(mLayoutInflater).inflate(anyInt(), eq(mSecurityViewFlipper), eq(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startDisappearAnimation_animatesKeyboard() {
|
||||
when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
|
||||
KeyguardSecurityModel.SecurityMode.Password);
|
||||
when(mKeyguardInputViewController.getSecurityMode()).thenReturn(
|
||||
KeyguardSecurityModel.SecurityMode.Password);
|
||||
when(mLayoutInflater.inflate(anyInt(), eq(mSecurityViewFlipper), eq(false)))
|
||||
.thenReturn(mInputView);
|
||||
mKeyguardSecurityContainerController.showPrimarySecurityScreen(false /* turningOff */);
|
||||
|
||||
mKeyguardSecurityContainerController.startDisappearAnimation(null);
|
||||
verify(mKeyguardInputViewController).startDisappearAnimation(eq(null));
|
||||
}
|
||||
}
|
||||
@@ -19,23 +19,19 @@ package com.android.keyguard;
|
||||
import static android.view.WindowInsets.Type.ime;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.WindowInsetsController;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
@@ -50,68 +46,26 @@ import org.mockito.junit.MockitoRule;
|
||||
@TestableLooper.RunWithLooper()
|
||||
public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
||||
|
||||
@Mock
|
||||
private KeyguardSecurityModel mKeyguardSecurityModel;
|
||||
@Mock
|
||||
private KeyguardStateController mKeyguardStateController;
|
||||
@Mock
|
||||
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
@Mock
|
||||
private KeyguardSecurityContainer.SecurityCallback mSecurityCallback;
|
||||
@Mock
|
||||
private KeyguardSecurityView mSecurityView;
|
||||
@Rule
|
||||
public MockitoRule mRule = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private WindowInsetsController mWindowInsetsController;
|
||||
@Mock
|
||||
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
|
||||
@Rule
|
||||
public MockitoRule mRule = MockitoJUnit.rule();
|
||||
|
||||
private KeyguardSecurityContainer mKeyguardSecurityContainer;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mDependency.injectTestDependency(KeyguardStateController.class, mKeyguardStateController);
|
||||
mDependency.injectTestDependency(KeyguardSecurityModel.class, mKeyguardSecurityModel);
|
||||
mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor);
|
||||
mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext()) {
|
||||
@Override
|
||||
protected KeyguardSecurityView getSecurityView(
|
||||
KeyguardSecurityModel.SecurityMode securityMode) {
|
||||
return mSecurityView;
|
||||
}
|
||||
};
|
||||
mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
|
||||
when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
|
||||
mKeyguardSecurityContainer.setSecurityCallback(mSecurityCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showSecurityScreen_canInflateAllModes() {
|
||||
Context context = getContext();
|
||||
|
||||
for (int theme : new int[] {R.style.Theme_SystemUI, R.style.Theme_SystemUI_Light}) {
|
||||
context.setTheme(theme);
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
KeyguardSecurityModel.SecurityMode[] modes =
|
||||
KeyguardSecurityModel.SecurityMode.values();
|
||||
for (KeyguardSecurityModel.SecurityMode mode : modes) {
|
||||
final int resId = mKeyguardSecurityContainer.getLayoutIdFor(mode);
|
||||
if (resId == 0) {
|
||||
continue;
|
||||
}
|
||||
inflater.inflate(resId, null /* root */, false /* attach */);
|
||||
}
|
||||
}
|
||||
mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext());
|
||||
mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startDisappearAnimation_animatesKeyboard() {
|
||||
when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
|
||||
KeyguardSecurityModel.SecurityMode.Password);
|
||||
mKeyguardSecurityContainer.showPrimarySecurityScreen(false /* turningOff */);
|
||||
|
||||
mKeyguardSecurityContainer.startDisappearAnimation(null);
|
||||
verify(mSecurityView).startDisappearAnimation(eq(null));
|
||||
mKeyguardSecurityContainer.startDisappearAnimation(SecurityMode.Password);
|
||||
verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(),
|
||||
any(), any());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user