diff options
14 files changed, 654 insertions, 903 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java index 23195af8bdea..e99245fa438f 100644 --- a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java +++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java @@ -33,13 +33,9 @@ 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. */ @@ -146,9 +142,9 @@ public class AdminSecondaryLockScreenController { } }; - private AdminSecondaryLockScreenController(Context context, KeyguardSecurityContainer parent, + public AdminSecondaryLockScreenController(Context context, ViewGroup parent, KeyguardUpdateMonitor updateMonitor, KeyguardSecurityCallback callback, - @Main Handler handler) { + Handler handler) { mContext = context; mHandler = handler; mParent = parent; @@ -238,26 +234,4 @@ 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); - } - } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java index 889309dd72e7..88f4176f5eac 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -28,6 +28,7 @@ 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; @@ -39,8 +40,8 @@ import com.android.systemui.R; /** * Base class for PIN and password unlock screens. */ -public abstract class KeyguardAbsKeyInputView extends KeyguardInputView - implements EmergencyButton.EmergencyButtonCallback { +public abstract class KeyguardAbsKeyInputView extends LinearLayout + implements KeyguardSecurityView, EmergencyButton.EmergencyButtonCallback { protected KeyguardSecurityCallback mCallback; protected LockPatternUtils mLockPatternUtils; protected AsyncTask<?, ?, ?> mPendingLockCheck; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java index b0a5533b0745..7aabb17de90c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java @@ -336,7 +336,7 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView> } public SecurityMode getCurrentSecurityMode() { - return mKeyguardSecurityContainerController.getCurrentSecuritySelection(); + return mKeyguardSecurityContainerController.getCurrentSecurityMode(); } public int getTop() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java deleted file mode 100644 index 976ec02e4f29..000000000000 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java +++ /dev/null @@ -1,42 +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.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); - } -} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java deleted file mode 100644 index b0b2cd8c74d9..000000000000 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ /dev/null @@ -1,160 +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.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); - } - } -} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index 44535bfef4ce..c4a9fcb45284 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -32,6 +32,7 @@ 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; @@ -47,8 +48,8 @@ import com.android.systemui.R; import java.util.List; -public class KeyguardPatternView extends KeyguardInputView - implements AppearAnimationCreator<LockPatternView.CellState>, +public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView, + AppearAnimationCreator<LockPatternView.CellState>, EmergencyButton.EmergencyButtonCallback { private static final String TAG = "SecurityPatternView"; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index e83795b70eed..81d37a830f8f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -19,6 +19,8 @@ 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; @@ -26,14 +28,25 @@ 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; @@ -48,30 +61,42 @@ 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 { - static final int USER_TYPE_PRIMARY = 1; - static final int USER_TYPE_WORK_PROFILE = 2; - static final int USER_TYPE_SECONDARY_USER = 3; +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; // Bouncer is dismissed due to no security. - static final int BOUNCER_DISMISS_NONE_SECURITY = 0; + private static final int BOUNCER_DISMISS_NONE_SECURITY = 0; // Bouncer is dismissed due to pin, password or pattern entered. - static final int BOUNCER_DISMISS_PASSWORD = 1; + private static final int BOUNCER_DISMISS_PASSWORD = 1; // Bouncer is dismissed due to biometric (face, fingerprint or iris) authenticated. - static final int BOUNCER_DISMISS_BIOMETRIC = 2; + private static final int BOUNCER_DISMISS_BIOMETRIC = 2; // Bouncer is dismissed due to extended access granted. - static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3; + private static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3; // Bouncer is dismissed due to sim card unlock code entered. - 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; @@ -80,23 +105,36 @@ public class KeyguardSecurityContainer extends FrameLayout { // 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) { @@ -146,28 +184,21 @@ public class KeyguardSecurityContainer extends FrameLayout { } }; - KeyguardSecurityViewFlipper getSecurityViewFlipper() { - return mSecurityViewFlipper; - } - // Used to notify the container when something interesting happens. public interface SecurityCallback { - boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen); - void userActivity(); - void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); + public boolean dismiss(boolean authenticated, int targetUserId, + boolean bypassSecondaryLockScreen); + public void userActivity(); + public 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. */ - void finish(boolean strongAuth, int targetUserId); - void reset(); - void onCancelClicked(); - } - - public interface SwipeListener { - void onSwipeUp(); + public void finish(boolean strongAuth, int targetUserId); + public void reset(); + public void onCancelClicked(); } @VisibleForTesting @@ -218,24 +249,52 @@ public class KeyguardSecurityContainer extends FrameLayout { 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; } - void onResume(SecurityMode securityMode, boolean faceAuthEnabled) { + @Override + public void onResume(int reason) { + if (mCurrentSecuritySelection != SecurityMode.None) { + getSecurityView(mCurrentSecuritySelection).onResume(reason); + } mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback); - updateBiometricRetry(securityMode, faceAuthEnabled); + updateBiometricRetry(); } + @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; } @@ -257,12 +316,13 @@ public class KeyguardSecurityContainer extends FrameLayout { return false; } // Avoid dragging the pattern view - if (mSecurityViewFlipper.getSecurityView().disallowInterceptTouch(event)) { + if (mCurrentSecurityView.disallowInterceptTouch(event)) { return false; } int index = event.findPointerIndex(mActivePointerId); float touchSlop = mViewConfiguration.getScaledTouchSlop() * SLOP_SCALE; - if (index != -1 && mStartTouchY - event.getY(index) > touchSlop) { + if (mCurrentSecurityView != null && index != -1 + && mStartTouchY - event.getY(index) > touchSlop) { mIsDragging = true; return true; } @@ -310,28 +370,31 @@ public class KeyguardSecurityContainer extends FrameLayout { } if (action == MotionEvent.ACTION_UP) { if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - MIN_DRAG_SIZE, getResources().getDisplayMetrics())) { - if (mSwipeListener != null) { - mSwipeListener.onSwipeUp(); - } + MIN_DRAG_SIZE, getResources().getDisplayMetrics()) + && !mUpdateMonitor.isFaceDetectionRunning()) { + mUpdateMonitor.requestFaceAuth(); + mCallback.userActivity(); + showMessage(null, null); } } return true; } - void setSwipeListener(SwipeListener swipeListener) { - mSwipeListener = swipeListener; - } - private void startSpringAnimation(float startVelocity) { mSpringAnimation .setStartVelocity(startVelocity) .animateToFinalPosition(0); } - public void startDisappearAnimation(SecurityMode securitySelection) { + public void startAppearAnimation() { + if (mCurrentSecuritySelection != SecurityMode.None) { + getSecurityView(mCurrentSecuritySelection).startAppearAnimation(); + } + } + + public boolean startDisappearAnimation(Runnable onFinishRunnable) { mDisappearAnimRunning = true; - if (securitySelection == SecurityMode.Password) { + if (mCurrentSecuritySelection == SecurityMode.Password) { mSecurityViewFlipper.getWindowInsetsController().controlWindowInsetsAnimation(ime(), IME_DISAPPEAR_DURATION_MS, Interpolators.LINEAR, null, new WindowInsetsAnimationControlListener() { @@ -376,13 +439,19 @@ public class KeyguardSecurityContainer extends FrameLayout { } }); } + 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, boolean faceAuthEnabled) { - mSwipeUpToRetry = faceAuthEnabled + private void updateBiometricRetry() { + SecurityMode securityMode = getSecurityMode(); + mSwipeUpToRetry = mKeyguardStateController.isFaceAuthEnabled() && securityMode != SecurityMode.SimPin && securityMode != SecurityMode.SimPuk && securityMode != SecurityMode.None; @@ -392,15 +461,53 @@ public class KeyguardSecurityContainer extends FrameLayout { 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) { - mSecurityViewFlipper.setLockPatternUtils(utils); + mLockPatternUtils = utils; + mSecurityModel.setLockPatternUtils(utils); + mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils); } @Override @@ -432,12 +539,11 @@ public class KeyguardSecurityContainer extends FrameLayout { mAlertDialog.show(); } - void showTimeoutDialog(int userId, int timeoutMs, LockPatternUtils lockPatternUtils, - SecurityMode securityMode) { - int timeoutInSeconds = timeoutMs / 1000; + private void showTimeoutDialog(int userId, int timeoutMs) { + int timeoutInSeconds = (int) timeoutMs / 1000; int messageId = 0; - switch (securityMode) { + switch (mSecurityModel.getSecurityMode(userId)) { case Pattern: messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message; break; @@ -457,13 +563,13 @@ public class KeyguardSecurityContainer extends FrameLayout { if (messageId != 0) { final String message = mContext.getString(messageId, - lockPatternUtils.getCurrentFailedPasswordAttempts(userId), + mLockPatternUtils.getCurrentFailedPasswordAttempts(userId), timeoutInSeconds); showDialog(null, message); } } - void showAlmostAtWipeDialog(int attempts, int remaining, int userType) { + private void showAlmostAtWipeDialog(int attempts, int remaining, int userType) { String message = null; switch (userType) { case USER_TYPE_PRIMARY: @@ -482,7 +588,7 @@ public class KeyguardSecurityContainer extends FrameLayout { showDialog(null, message); } - void showWipeDialog(int attempts, int userType) { + private void showWipeDialog(int attempts, int userType) { String message = null; switch (userType) { case USER_TYPE_PRIMARY: @@ -501,19 +607,356 @@ public class KeyguardSecurityContainer extends FrameLayout { 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(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 11f951be9a15..17f25bd08ef4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -16,197 +16,33 @@ package com.android.keyguard; -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> - implements KeyguardSecurityView { +public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer> { - private static final boolean DEBUG = KeyguardConstants.DEBUG; - private static final String TAG = "KeyguardSecurityView"; - - private final AdminSecondaryLockScreenController mAdminSecondaryLockScreenController; private final LockPatternUtils mLockPatternUtils; - 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); - } - } - }; + private final KeyguardSecurityViewController.Factory mKeyguardSecurityViewControllerFactory; @Inject KeyguardSecurityContainerController(KeyguardSecurityContainer view, - AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory, LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor keyguardUpdateMonitor, - KeyguardSecurityModel keyguardSecurityModel, - MetricsLogger metricsLogger, - UiEventLogger uiEventLogger, - KeyguardStateController keyguardStateController, - LayoutInflater layoutInflater, - InjectionInflationController injectionInflationController, - KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory) { + KeyguardSecurityViewController.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 @@ -215,48 +51,27 @@ 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) { - SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode( - KeyguardUpdateMonitor.getCurrentUser())); - if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")"); - showSecurityScreen(securityMode); + mView.showPrimarySecurityScreen(turningOff); } - @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); - } + mView.showPromptReason(reason); } public void showMessage(CharSequence message, ColorStateList colorState) { - if (mCurrentSecuritySelection != SecurityMode.None) { - getSecurityView(mCurrentSecuritySelection).showMessage(message, colorState); - } + mView.showMessage(message, colorState); } public SecurityMode getCurrentSecuritySelection() { - return mCurrentSecuritySelection; + return mView.getCurrentSecuritySelection(); } public void dismiss(boolean authenticated, int targetUserId) { - mKeyguardSecurityCallback.dismiss(authenticated, targetUserId); + mView.dismiss(authenticated, targetUserId); } public void reset() { @@ -267,276 +82,37 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard return mView.getTitle(); } - @Override - public void onResume(int reason) { - if (mCurrentSecuritySelection != SecurityMode.None) { - getSecurityView(mCurrentSecuritySelection).onResume(reason); - } - mView.onResume( - mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()), - mKeyguardStateController.isFaceAuthEnabled()); + public void onResume(int screenOn) { + mView.onResume(screenOn); } public void startAppearAnimation() { - if (mCurrentSecuritySelection != SecurityMode.None) { - getSecurityView(mCurrentSecuritySelection).startAppearAnimation(); - } + mView.startAppearAnimation(); } public boolean startDisappearAnimation(Runnable onFinishRunnable) { - mView.startDisappearAnimation(getCurrentSecuritySelection()); - - if (mCurrentSecuritySelection != SecurityMode.None) { - return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation( - onFinishRunnable); - } - - return false; + return mView.startDisappearAnimation(onFinishRunnable); } public void onStartingToHide() { - if (mCurrentSecuritySelection != SecurityMode.None) { - getSecurityView(mCurrentSecuritySelection).onStartingToHide(); - } + mView.onStartingToHide(); } public void setSecurityCallback(SecurityCallback securityCallback) { - mSecurityCallback = securityCallback; + mView.setSecurityCallback(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) { - - 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; + return mView.showNextSecurityScreenOrFinish( + authenticated, targetUserId, bypassSecondaryLockScreen); } public boolean needsInput() { return mView.needsInput(); } - - /** - * 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; + public SecurityMode getCurrentSecurityMode() { + return mView.getCurrentSecurityMode(); } - - 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; - } - } - } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java index c77c86711abf..ac2160ecb4ae 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java @@ -18,14 +18,13 @@ package com.android.keyguard; import static com.android.systemui.DejankUtils.whitelistIpcs; import android.app.admin.DevicePolicyManager; -import android.content.res.Resources; +import android.content.Context; 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; @@ -34,7 +33,7 @@ public class KeyguardSecurityModel { /** * The different types of security available. - * @see KeyguardSecurityContainerController#showSecurityScreen + * @see KeyguardSecurityContainer#showSecurityScreen */ public enum SecurityMode { Invalid, // NULL state @@ -46,15 +45,21 @@ public class KeyguardSecurityModel { SimPuk // Unlock by entering a sim puk } + private final Context mContext; private final boolean mIsPukScreenAvailable; - private final LockPatternUtils mLockPatternUtils; + private LockPatternUtils mLockPatternUtils; @Inject - KeyguardSecurityModel(@Main Resources resources, LockPatternUtils lockPatternUtils) { - mIsPukScreenAvailable = resources.getBoolean( + KeyguardSecurityModel(Context context) { + mContext = context; + mLockPatternUtils = new LockPatternUtils(context); + mIsPukScreenAvailable = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enable_puk_unlock_screen); - mLockPatternUtils = lockPatternUtils; + } + + void setLockPatternUtils(LockPatternUtils utils) { + mLockPatternUtils = utils; } public SecurityMode getSecurityMode(int userId) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java new file mode 100644 index 000000000000..ef9ba19fbb43 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java @@ -0,0 +1,58 @@ +/* + * 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); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index eb431274b8a3..38e12a6ed5f8 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -288,7 +288,6 @@ public class DependencyProvider { /** */ @Provides - @SysUISingleton public LockPatternUtils provideLockPatternUtils(Context context) { return new LockPatternUtils(context); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java index dffad6ccbea5..9be2d124026c 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java @@ -41,6 +41,8 @@ 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; @@ -65,7 +67,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase { private ComponentName mComponentName; private Intent mServiceIntent; private TestableLooper mTestableLooper; - private KeyguardSecurityContainer mKeyguardSecurityContainer; + private ViewGroup mParent; @Mock private Handler mHandler; @@ -82,8 +84,8 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); - mKeyguardSecurityContainer = spy(new KeyguardSecurityContainer(mContext)); - ViewUtils.attachView(mKeyguardSecurityContainer); + mParent = spy(new FrameLayout(mContext)); + ViewUtils.attachView(mParent); mTestableLooper = TestableLooper.get(this); mComponentName = new ComponentName(mContext, "FakeKeyguardClient.class"); @@ -94,14 +96,13 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase { when(mKeyguardClient.queryLocalInterface(anyString())).thenReturn(mKeyguardClient); when(mKeyguardClient.asBinder()).thenReturn(mKeyguardClient); - mTestController = new AdminSecondaryLockScreenController.Factory( - mContext, mKeyguardSecurityContainer, mUpdateMonitor, mHandler) - .create(mKeyguardCallback); + mTestController = new AdminSecondaryLockScreenController( + mContext, mParent, mUpdateMonitor, mKeyguardCallback, mHandler); } @After public void tearDown() { - ViewUtils.detachView(mKeyguardSecurityContainer); + ViewUtils.detachView(mParent); } @Test @@ -145,7 +146,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase { SurfaceView v = verifySurfaceReady(); mTestController.hide(); - verify(mKeyguardSecurityContainer).removeView(v); + verify(mParent).removeView(v); assertThat(mContext.isBound(mComponentName)).isFalse(); } @@ -153,7 +154,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(mKeyguardSecurityContainer, never()).removeView(any(SurfaceView.class)); + verify(mParent, never()).removeView(any(SurfaceView.class)); } @Test @@ -181,7 +182,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase { private SurfaceView verifySurfaceReady() throws Exception { mTestableLooper.processAllMessages(); ArgumentCaptor<SurfaceView> captor = ArgumentCaptor.forClass(SurfaceView.class); - verify(mKeyguardSecurityContainer).addView(captor.capture()); + verify(mParent).addView(captor.capture()); mTestableLooper.processAllMessages(); verify(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class)); @@ -189,7 +190,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase { } private void verifyViewDismissed(SurfaceView v) throws Exception { - verify(mKeyguardSecurityContainer).removeView(v); + verify(mParent).removeView(v); verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true); assertThat(mContext.isBound(mComponentName)).isFalse(); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java deleted file mode 100644 index 560b15948591..000000000000 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ /dev/null @@ -1,151 +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 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)); - } -} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 854be1f76722..a867825e223d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -19,19 +19,23 @@ 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.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; import org.junit.Rule; @@ -46,26 +50,68 @@ import org.mockito.junit.MockitoRule; @TestableLooper.RunWithLooper() public class KeyguardSecurityContainerTest extends SysuiTestCase { - @Rule - public MockitoRule mRule = MockitoJUnit.rule(); - + @Mock + private KeyguardSecurityModel mKeyguardSecurityModel; + @Mock + private KeyguardStateController mKeyguardStateController; + @Mock + private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock + private KeyguardSecurityContainer.SecurityCallback mSecurityCallback; + @Mock + private KeyguardSecurityView mSecurityView; @Mock private WindowInsetsController mWindowInsetsController; @Mock private KeyguardSecurityViewFlipper mSecurityViewFlipper; - + @Rule + public MockitoRule mRule = MockitoJUnit.rule(); private KeyguardSecurityContainer mKeyguardSecurityContainer; @Before public void setup() { - when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController); - mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext()); + 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 */); + } + } } @Test public void startDisappearAnimation_animatesKeyboard() { - mKeyguardSecurityContainer.startDisappearAnimation(SecurityMode.Password); + when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn( + KeyguardSecurityModel.SecurityMode.Password); + mKeyguardSecurityContainer.showPrimarySecurityScreen(false /* turningOff */); + + mKeyguardSecurityContainer.startDisappearAnimation(null); + verify(mSecurityView).startDisappearAnimation(eq(null)); verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(), any(), any()); } |