diff options
| author | 2020-09-02 15:26:42 -0400 | |
|---|---|---|
| committer | 2020-09-16 16:24:11 -0400 | |
| commit | 8f75cf99445bae63bb46602de9b6a0a3b6fad2bf (patch) | |
| tree | ee4924cf114953b3a22545037081c4782ce3e881 | |
| parent | e1e67c57a67fd3d742df254c34745a31d5eb4400 (diff) | |
4/N Setup Controller fo KeyguardSecurityContainer.
Move the guts of KeyguardSecurityContainer into
KeyguardSecurityContainerController. This removes a lot of
Dependency#get calls, and is another step towards simplifying our
view inflation process.
CustomViews that previously implemented KeyguardSecurityView now
all extend KeyguardInputView, allowing them to be simultaneously
treated as one while also being recognized as a View (the interface
required a lot of casting back and forth to a View).
LockscreenUtil is made a Singleton in this CL.
Bug: 166448040
Test: atest SystemUITests && manual
Change-Id: I6fa05012c55f5e003ab551d2f8360891a62fa2a7
14 files changed, 903 insertions, 654 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java index e99245fa438f..23195af8bdea 100644 --- a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java +++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java @@ -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); + } + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java index 88f4176f5eac..889309dd72e7 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -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; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java index 7aabb17de90c..b0a5533b0745 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.getCurrentSecurityMode(); + return mKeyguardSecurityContainerController.getCurrentSecuritySelection(); } public int getTop() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java new file mode 100644 index 000000000000..976ec02e4f29 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java @@ -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); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java new file mode 100644 index 000000000000..b0b2cd8c74d9 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -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); + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index c4a9fcb45284..44535bfef4ce 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -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"; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 05172279c4ed..60e34c804bc2 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -21,8 +21,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; @@ -30,25 +28,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; @@ -63,42 +50,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; @@ -107,36 +82,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) { @@ -186,21 +148,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 @@ -251,52 +220,24 @@ 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; } @@ -318,13 +259,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; } @@ -372,31 +312,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() { @@ -441,19 +378,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; @@ -463,53 +394,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 @@ -546,11 +439,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; @@ -570,13 +464,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: @@ -595,7 +489,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: @@ -614,356 +508,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(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 17f25bd08ef4..11f951be9a15 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -16,33 +16,197 @@ 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> { +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; + } + } + } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java index ac2160ecb4ae..c77c86711abf 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java @@ -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) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java deleted file mode 100644 index ef9ba19fbb43..000000000000 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java +++ /dev/null @@ -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); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index 38e12a6ed5f8..eb431274b8a3 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -288,6 +288,7 @@ 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 9be2d124026c..dffad6ccbea5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java @@ -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(); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java new file mode 100644 index 000000000000..560b15948591 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -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)); + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index a867825e223d..854be1f76722 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -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()); } |