From cf2591fa361b6a046ead5b2c17ae0e9296200bb0 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Wed, 23 Sep 2020 14:01:33 +0000 Subject: [PATCH 1/7] Revert^2 "4/N Setup Controller fo KeyguardSecurityContainer." 0d6a9012a73a2d999d52aaefca0a6ad52322db31 Change-Id: I881bbcdc63fcbafa8966064cccb7ce1edc710062 --- .../AdminSecondaryLockScreenController.java | 30 +- .../keyguard/KeyguardAbsKeyInputView.java | 5 +- .../keyguard/KeyguardHostViewController.java | 2 +- .../android/keyguard/KeyguardInputView.java | 42 ++ .../keyguard/KeyguardInputViewController.java | 160 ++++++ .../android/keyguard/KeyguardPatternView.java | 5 +- .../keyguard/KeyguardSecurityContainer.java | 539 ++---------------- .../KeyguardSecurityContainerController.java | 462 ++++++++++++++- .../keyguard/KeyguardSecurityModel.java | 19 +- .../KeyguardSecurityViewController.java | 58 -- .../systemui/dagger/DependencyProvider.java | 1 + ...dminSecondaryLockScreenControllerTest.java | 23 +- ...yguardSecurityContainerControllerTest.java | 151 +++++ .../KeyguardSecurityContainerTest.java | 62 +- 14 files changed, 904 insertions(+), 655 deletions(-) create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java delete mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java create mode 100644 packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java index e99245fa438f7..23195af8bdea2 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 88f4176f5eaca..889309dd72e72 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 7aabb17de90cd..b0a5533b0745a 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 } 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 0000000000000..976ec02e4f29d --- /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 0000000000000..b0b2cd8c74d97 --- /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 + 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 c4a9fcb452842..44535bfef4ce0 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, +public class KeyguardPatternView extends KeyguardInputView + implements AppearAnimationCreator, 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 81d37a830f8f4..e83795b70eed7 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -19,8 +19,6 @@ import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.systemBars; import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP; -import static com.android.systemui.DejankUtils.whitelistIpcs; - import static java.lang.Integer.max; import android.animation.Animator; @@ -28,25 +26,14 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.Activity; import android.app.AlertDialog; -import android.app.admin.DevicePolicyManager; import android.content.Context; -import android.content.Intent; -import android.content.res.ColorStateList; import android.graphics.Insets; import android.graphics.Rect; -import android.metrics.LogMaker; -import android.os.Handler; -import android.os.Looper; -import android.os.UserHandle; import android.util.AttributeSet; -import android.util.Log; import android.util.MathUtils; -import android.util.Slog; import android.util.TypedValue; -import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.VelocityTracker; -import android.view.View; import android.view.ViewConfiguration; import android.view.WindowInsets; import android.view.WindowInsetsAnimation; @@ -61,42 +48,30 @@ import androidx.annotation.VisibleForTesting; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; -import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; -import com.android.internal.logging.UiEventLoggerImpl; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import com.android.settingslib.utils.ThreadUtils; -import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; -import com.android.systemui.shared.system.SysUiStatsLog; -import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.util.InjectionInflationController; import java.util.List; -public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView { - private static final boolean DEBUG = KeyguardConstants.DEBUG; - private static final String TAG = "KeyguardSecurityView"; - - private static final int USER_TYPE_PRIMARY = 1; - private static final int USER_TYPE_WORK_PROFILE = 2; - private static final int USER_TYPE_SECONDARY_USER = 3; +public class KeyguardSecurityContainer extends FrameLayout { + static final int USER_TYPE_PRIMARY = 1; + static final int USER_TYPE_WORK_PROFILE = 2; + static final int USER_TYPE_SECONDARY_USER = 3; // Bouncer is dismissed due to no security. - private static final int BOUNCER_DISMISS_NONE_SECURITY = 0; + static final int BOUNCER_DISMISS_NONE_SECURITY = 0; // Bouncer is dismissed due to pin, password or pattern entered. - private static final int BOUNCER_DISMISS_PASSWORD = 1; + static final int BOUNCER_DISMISS_PASSWORD = 1; // Bouncer is dismissed due to biometric (face, fingerprint or iris) authenticated. - private static final int BOUNCER_DISMISS_BIOMETRIC = 2; + static final int BOUNCER_DISMISS_BIOMETRIC = 2; // Bouncer is dismissed due to extended access granted. - private static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3; + static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3; // Bouncer is dismissed due to sim card unlock code entered. - private static final int BOUNCER_DISMISS_SIM = 4; + static final int BOUNCER_DISMISS_SIM = 4; // Make the view move slower than the finger, as if the spring were applying force. private static final float TOUCH_Y_MULTIPLIER = 0.25f; @@ -105,36 +80,23 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe // How much to scale the default slop by, to avoid accidental drags. private static final float SLOP_SCALE = 4f; - private static final UiEventLogger sUiEventLogger = new UiEventLoggerImpl(); - private static final long IME_DISAPPEAR_DURATION_MS = 125; - private KeyguardSecurityModel mSecurityModel; - private LockPatternUtils mLockPatternUtils; - @VisibleForTesting KeyguardSecurityViewFlipper mSecurityViewFlipper; - private boolean mIsVerifyUnlockOnly; - private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid; - private KeyguardSecurityView mCurrentSecurityView; - private SecurityCallback mSecurityCallback; private AlertDialog mAlertDialog; - private InjectionInflationController mInjectionInflationController; private boolean mSwipeUpToRetry; - private AdminSecondaryLockScreenController mSecondaryLockScreenController; private final ViewConfiguration mViewConfiguration; private final SpringAnimation mSpringAnimation; private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); - private final KeyguardUpdateMonitor mUpdateMonitor; - private final KeyguardStateController mKeyguardStateController; - private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); private float mLastTouchY = -1; private int mActivePointerId = -1; private boolean mIsDragging; private float mStartTouchY = -1; private boolean mDisappearAnimRunning; + private SwipeListener mSwipeListener; private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback = new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { @@ -184,21 +146,28 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe } }; + KeyguardSecurityViewFlipper getSecurityViewFlipper() { + return mSecurityViewFlipper; + } + // Used to notify the container when something interesting happens. public interface SecurityCallback { - public boolean dismiss(boolean authenticated, int targetUserId, - boolean bypassSecondaryLockScreen); - public void userActivity(); - public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); + boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen); + void userActivity(); + void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); /** * @param strongAuth wheher the user has authenticated with strong authentication like * pattern, password or PIN but not by trust agents or fingerprint * @param targetUserId a user that needs to be the foreground user at the finish completion. */ - public void finish(boolean strongAuth, int targetUserId); - public void reset(); - public void onCancelClicked(); + void finish(boolean strongAuth, int targetUserId); + void reset(); + void onCancelClicked(); + } + + public interface SwipeListener { + void onSwipeUp(); } @VisibleForTesting @@ -249,51 +218,23 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mSecurityModel = Dependency.get(KeyguardSecurityModel.class); - mLockPatternUtils = new LockPatternUtils(context); - mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y); - mInjectionInflationController = new InjectionInflationController( - SystemUIFactory.getInstance().getSysUIComponent().createViewInstanceCreatorFactory()); mViewConfiguration = ViewConfiguration.get(context); - mKeyguardStateController = Dependency.get(KeyguardStateController.class); - mSecondaryLockScreenController = new AdminSecondaryLockScreenController(context, this, - mUpdateMonitor, mCallback, new Handler(Looper.myLooper())); } - public void setSecurityCallback(SecurityCallback callback) { - mSecurityCallback = callback; - } - - @Override - public void onResume(int reason) { - if (mCurrentSecuritySelection != SecurityMode.None) { - getSecurityView(mCurrentSecuritySelection).onResume(reason); - } + void onResume(SecurityMode securityMode, boolean faceAuthEnabled) { mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback); - updateBiometricRetry(); + updateBiometricRetry(securityMode, faceAuthEnabled); } - @Override public void onPause() { if (mAlertDialog != null) { mAlertDialog.dismiss(); mAlertDialog = null; } - mSecondaryLockScreenController.hide(); - if (mCurrentSecuritySelection != SecurityMode.None) { - getSecurityView(mCurrentSecuritySelection).onPause(); - } mSecurityViewFlipper.setWindowInsetsAnimationCallback(null); } - @Override - public void onStartingToHide() { - if (mCurrentSecuritySelection != SecurityMode.None) { - getSecurityView(mCurrentSecuritySelection).onStartingToHide(); - } - } - @Override public boolean shouldDelayChildPressedState() { return true; @@ -316,13 +257,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe return false; } // Avoid dragging the pattern view - if (mCurrentSecurityView.disallowInterceptTouch(event)) { + if (mSecurityViewFlipper.getSecurityView().disallowInterceptTouch(event)) { return false; } int index = event.findPointerIndex(mActivePointerId); float touchSlop = mViewConfiguration.getScaledTouchSlop() * SLOP_SCALE; - if (mCurrentSecurityView != null && index != -1 - && mStartTouchY - event.getY(index) > touchSlop) { + if (index != -1 && mStartTouchY - event.getY(index) > touchSlop) { mIsDragging = true; return true; } @@ -370,31 +310,28 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe } if (action == MotionEvent.ACTION_UP) { if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - MIN_DRAG_SIZE, getResources().getDisplayMetrics()) - && !mUpdateMonitor.isFaceDetectionRunning()) { - mUpdateMonitor.requestFaceAuth(); - mCallback.userActivity(); - showMessage(null, null); + MIN_DRAG_SIZE, getResources().getDisplayMetrics())) { + if (mSwipeListener != null) { + mSwipeListener.onSwipeUp(); + } } } return true; } + void setSwipeListener(SwipeListener swipeListener) { + mSwipeListener = swipeListener; + } + private void startSpringAnimation(float startVelocity) { mSpringAnimation .setStartVelocity(startVelocity) .animateToFinalPosition(0); } - public void startAppearAnimation() { - if (mCurrentSecuritySelection != SecurityMode.None) { - getSecurityView(mCurrentSecuritySelection).startAppearAnimation(); - } - } - - public boolean startDisappearAnimation(Runnable onFinishRunnable) { + public void startDisappearAnimation(SecurityMode securitySelection) { mDisappearAnimRunning = true; - if (mCurrentSecuritySelection == SecurityMode.Password) { + if (securitySelection == SecurityMode.Password) { mSecurityViewFlipper.getWindowInsetsController().controlWindowInsetsAnimation(ime(), IME_DISAPPEAR_DURATION_MS, Interpolators.LINEAR, null, new WindowInsetsAnimationControlListener() { @@ -439,19 +376,13 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe } }); } - if (mCurrentSecuritySelection != SecurityMode.None) { - return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation( - onFinishRunnable); - } - return false; } /** * Enables/disables swipe up to retry on the bouncer. */ - private void updateBiometricRetry() { - SecurityMode securityMode = getSecurityMode(); - mSwipeUpToRetry = mKeyguardStateController.isFaceAuthEnabled() + private void updateBiometricRetry(SecurityMode securityMode, boolean faceAuthEnabled) { + mSwipeUpToRetry = faceAuthEnabled && securityMode != SecurityMode.SimPin && securityMode != SecurityMode.SimPuk && securityMode != SecurityMode.None; @@ -461,53 +392,15 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe return mSecurityViewFlipper.getTitle(); } - @VisibleForTesting - protected KeyguardSecurityView getSecurityView(SecurityMode securityMode) { - final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); - KeyguardSecurityView view = null; - final int children = mSecurityViewFlipper.getChildCount(); - for (int child = 0; child < children; child++) { - if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) { - view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child)); - break; - } - } - int layoutId = getLayoutIdFor(securityMode); - if (view == null && layoutId != 0) { - final LayoutInflater inflater = LayoutInflater.from(mContext); - if (DEBUG) Log.v(TAG, "inflating id = " + layoutId); - View v = mInjectionInflationController.injectable(inflater) - .inflate(layoutId, mSecurityViewFlipper, false); - mSecurityViewFlipper.addView(v); - updateSecurityView(v); - view = (KeyguardSecurityView)v; - view.reset(); - } - - return view; - } - - private void updateSecurityView(View view) { - if (view instanceof KeyguardSecurityView) { - KeyguardSecurityView ksv = (KeyguardSecurityView) view; - ksv.setKeyguardCallback(mCallback); - ksv.setLockPatternUtils(mLockPatternUtils); - } else { - Log.w(TAG, "View " + view + " is not a KeyguardSecurityView"); - } - } @Override public void onFinishInflate() { super.onFinishInflate(); mSecurityViewFlipper = findViewById(R.id.view_flipper); - mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils); } public void setLockPatternUtils(LockPatternUtils utils) { - mLockPatternUtils = utils; - mSecurityModel.setLockPatternUtils(utils); - mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils); + mSecurityViewFlipper.setLockPatternUtils(utils); } @Override @@ -539,11 +432,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe mAlertDialog.show(); } - private void showTimeoutDialog(int userId, int timeoutMs) { - int timeoutInSeconds = (int) timeoutMs / 1000; + void showTimeoutDialog(int userId, int timeoutMs, LockPatternUtils lockPatternUtils, + SecurityMode securityMode) { + int timeoutInSeconds = timeoutMs / 1000; int messageId = 0; - switch (mSecurityModel.getSecurityMode(userId)) { + switch (securityMode) { case Pattern: messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message; break; @@ -563,13 +457,13 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe if (messageId != 0) { final String message = mContext.getString(messageId, - mLockPatternUtils.getCurrentFailedPasswordAttempts(userId), + lockPatternUtils.getCurrentFailedPasswordAttempts(userId), timeoutInSeconds); showDialog(null, message); } } - private void showAlmostAtWipeDialog(int attempts, int remaining, int userType) { + void showAlmostAtWipeDialog(int attempts, int remaining, int userType) { String message = null; switch (userType) { case USER_TYPE_PRIMARY: @@ -588,7 +482,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe showDialog(null, message); } - private void showWipeDialog(int attempts, int userType) { + void showWipeDialog(int attempts, int userType) { String message = null; switch (userType) { case USER_TYPE_PRIMARY: @@ -607,356 +501,19 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe showDialog(null, message); } - private void reportFailedUnlockAttempt(int userId, int timeoutMs) { - // +1 for this time - final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1; - - if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts); - - final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager(); - final int failedAttemptsBeforeWipe = - dpm.getMaximumFailedPasswordsForWipe(null, userId); - - final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ? - (failedAttemptsBeforeWipe - failedAttempts) - : Integer.MAX_VALUE; // because DPM returns 0 if no restriction - if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { - // The user has installed a DevicePolicyManager that requests a user/profile to be wiped - // N attempts. Once we get below the grace period, we post this dialog every time as a - // clear warning until the deletion fires. - // Check which profile has the strictest policy for failed password attempts - final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId); - int userType = USER_TYPE_PRIMARY; - if (expiringUser == userId) { - // TODO: http://b/23522538 - if (expiringUser != UserHandle.USER_SYSTEM) { - userType = USER_TYPE_SECONDARY_USER; - } - } else if (expiringUser != UserHandle.USER_NULL) { - userType = USER_TYPE_WORK_PROFILE; - } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY - if (remainingBeforeWipe > 0) { - showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType); - } else { - // Too many attempts. The device will be wiped shortly. - Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!"); - showWipeDialog(failedAttempts, userType); - } - } - mLockPatternUtils.reportFailedPasswordAttempt(userId); - if (timeoutMs > 0) { - mLockPatternUtils.reportPasswordLockout(timeoutMs, userId); - showTimeoutDialog(userId, timeoutMs); - } - } - - /** - * Shows the primary security screen for the user. This will be either the multi-selector - * or the user's security method. - * @param turningOff true if the device is being turned off - */ - void showPrimarySecurityScreen(boolean turningOff) { - SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode( - KeyguardUpdateMonitor.getCurrentUser())); - if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")"); - showSecurityScreen(securityMode); - } - - /** - * Shows the next security screen if there is one. - * @param authenticated true if the user entered the correct authentication - * @param targetUserId a user that needs to be the foreground user at the finish (if called) - * completion. - * @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary - * secondary lock screen requirement, if any. - * @return true if keyguard is done - */ - boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId, - boolean bypassSecondaryLockScreen) { - if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); - boolean finish = false; - boolean strongAuth = false; - int eventSubtype = -1; - BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN; - if (mUpdateMonitor.getUserHasTrust(targetUserId)) { - finish = true; - eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS; - uiEvent = BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS; - } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) { - finish = true; - eventSubtype = BOUNCER_DISMISS_BIOMETRIC; - uiEvent = BouncerUiEvent.BOUNCER_DISMISS_BIOMETRIC; - } else if (SecurityMode.None == mCurrentSecuritySelection) { - SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId); - if (SecurityMode.None == securityMode) { - finish = true; // no security required - eventSubtype = BOUNCER_DISMISS_NONE_SECURITY; - uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY; - } else { - showSecurityScreen(securityMode); // switch to the alternate security view - } - } else if (authenticated) { - switch (mCurrentSecuritySelection) { - case Pattern: - case Password: - case PIN: - strongAuth = true; - finish = true; - eventSubtype = BOUNCER_DISMISS_PASSWORD; - uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD; - break; - - case SimPin: - case SimPuk: - // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home - SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId); - if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled( - KeyguardUpdateMonitor.getCurrentUser())) { - finish = true; - eventSubtype = BOUNCER_DISMISS_SIM; - uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM; - } else { - showSecurityScreen(securityMode); - } - break; - - default: - Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe"); - showPrimarySecurityScreen(false); - break; - } - } - // Check for device admin specified additional security measures. - if (finish && !bypassSecondaryLockScreen) { - Intent secondaryLockscreenIntent = - mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId); - if (secondaryLockscreenIntent != null) { - mSecondaryLockScreenController.show(secondaryLockscreenIntent); - return false; - } - } - if (eventSubtype != -1) { - mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER) - .setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype)); - } - if (uiEvent != BouncerUiEvent.UNKNOWN) { - sUiEventLogger.log(uiEvent); - } - if (finish) { - mSecurityCallback.finish(strongAuth, targetUserId); - } - return finish; - } - - /** - * Switches to the given security view unless it's already being shown, in which case - * this is a no-op. - * - * @param securityMode - */ - private void showSecurityScreen(SecurityMode securityMode) { - if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")"); - - if (securityMode == mCurrentSecuritySelection) return; - - KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection); - KeyguardSecurityView newView = getSecurityView(securityMode); - - // Emulate Activity life cycle - if (oldView != null) { - oldView.onPause(); - oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view - } - if (securityMode != SecurityMode.None) { - newView.onResume(KeyguardSecurityView.VIEW_REVEALED); - newView.setKeyguardCallback(mCallback); - } - - // Find and show this child. - final int childCount = mSecurityViewFlipper.getChildCount(); - - final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); - for (int i = 0; i < childCount; i++) { - if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) { - mSecurityViewFlipper.setDisplayedChild(i); - break; - } - } - - mCurrentSecuritySelection = securityMode; - mCurrentSecurityView = newView; - mSecurityCallback.onSecurityModeChanged(securityMode, - securityMode != SecurityMode.None && newView.needsInput()); - } - - private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() { - public void userActivity() { - if (mSecurityCallback != null) { - mSecurityCallback.userActivity(); - } - } - - @Override - public void onUserInput() { - mUpdateMonitor.cancelFaceAuth(); - } - - @Override - public void dismiss(boolean authenticated, int targetId) { - dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false); - } - - @Override - public void dismiss(boolean authenticated, int targetId, - boolean bypassSecondaryLockScreen) { - mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen); - } - - public boolean isVerifyUnlockOnly() { - return mIsVerifyUnlockOnly; - } - - public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { - if (success) { - SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED, - SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS); - mLockPatternUtils.reportSuccessfulPasswordAttempt(userId); - // Force a garbage collection in an attempt to erase any lockscreen password left in - // memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard - // dismiss animation janky. - ThreadUtils.postOnBackgroundThread(() -> { - try { - Thread.sleep(5000); - } catch (InterruptedException ignored) { } - Runtime.getRuntime().gc(); - }); - } else { - SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED, - SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE); - KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs); - } - mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER) - .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE)); - sUiEventLogger.log(success ? BouncerUiEvent.BOUNCER_PASSWORD_SUCCESS - : BouncerUiEvent.BOUNCER_PASSWORD_FAILURE); - } - - public void reset() { - mSecurityCallback.reset(); - } - - public void onCancelClicked() { - mSecurityCallback.onCancelClicked(); - } - }; - - // The following is used to ignore callbacks from SecurityViews that are no longer current - // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the - // state for the current security method. - private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() { - @Override - public void userActivity() { } - @Override - public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { } - @Override - public boolean isVerifyUnlockOnly() { return false; } - @Override - public void dismiss(boolean securityVerified, int targetUserId) { } - @Override - public void dismiss(boolean authenticated, int targetId, - boolean bypassSecondaryLockScreen) { } - @Override - public void onUserInput() { } - @Override - public void reset() {} - }; - - private int getSecurityViewIdForMode(SecurityMode securityMode) { - switch (securityMode) { - case Pattern: return R.id.keyguard_pattern_view; - case PIN: return R.id.keyguard_pin_view; - case Password: return R.id.keyguard_password_view; - case SimPin: return R.id.keyguard_sim_pin_view; - case SimPuk: return R.id.keyguard_sim_puk_view; - } - return 0; - } - - @VisibleForTesting - public int getLayoutIdFor(SecurityMode securityMode) { - switch (securityMode) { - case Pattern: return R.layout.keyguard_pattern_view; - case PIN: return R.layout.keyguard_pin_view; - case Password: return R.layout.keyguard_password_view; - case SimPin: return R.layout.keyguard_sim_pin_view; - case SimPuk: return R.layout.keyguard_sim_puk_view; - default: - return 0; - } - } - - public SecurityMode getSecurityMode() { - return mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()); - } - - public SecurityMode getCurrentSecurityMode() { - return mCurrentSecuritySelection; - } - - public KeyguardSecurityView getCurrentSecurityView() { - return mCurrentSecurityView; - } - - public void verifyUnlock() { - mIsVerifyUnlockOnly = true; - showSecurityScreen(getSecurityMode()); - } - - public SecurityMode getCurrentSecuritySelection() { - return mCurrentSecuritySelection; - } - - public void dismiss(boolean authenticated, int targetUserId) { - mCallback.dismiss(authenticated, targetUserId); - } - public boolean needsInput() { return mSecurityViewFlipper.needsInput(); } - @Override - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mSecurityViewFlipper.setKeyguardCallback(callback); - } - - @Override public void reset() { mSecurityViewFlipper.reset(); mDisappearAnimRunning = false; } - @Override public KeyguardSecurityCallback getCallback() { return mSecurityViewFlipper.getCallback(); } - @Override - public void showPromptReason(int reason) { - if (mCurrentSecuritySelection != SecurityMode.None) { - if (reason != PROMPT_REASON_NONE) { - Log.i(TAG, "Strong auth required, reason: " + reason); - } - getSecurityView(mCurrentSecuritySelection).showPromptReason(reason); - } - } - - public void showMessage(CharSequence message, ColorStateList colorState) { - if (mCurrentSecuritySelection != SecurityMode.None) { - getSecurityView(mCurrentSecuritySelection).showMessage(message, colorState); - } - } - - @Override public void showUsabilityHint() { mSecurityViewFlipper.showUsabilityHint(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 17f25bd08ef49..11f951be9a152 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 android.content.res.ColorStateList; +import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC; +import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS; +import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY; +import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_PASSWORD; +import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_SIM; +import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_PRIMARY; +import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER; +import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE; +import static com.android.systemui.DejankUtils.whitelistIpcs; +import android.app.admin.DevicePolicyManager; +import android.content.Intent; +import android.content.res.ColorStateList; +import android.metrics.LogMaker; +import android.os.UserHandle; +import android.util.Log; +import android.util.Slog; +import android.view.LayoutInflater; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent; import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback; +import com.android.keyguard.KeyguardSecurityContainer.SwipeListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.settingslib.utils.ThreadUtils; +import com.android.systemui.R; +import com.android.systemui.shared.system.SysUiStatsLog; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.ViewController; +import java.util.ArrayList; +import java.util.List; + import javax.inject.Inject; /** Controller for {@link KeyguardSecurityContainer} */ -public class KeyguardSecurityContainerController extends ViewController { +public class KeyguardSecurityContainerController extends ViewController + 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 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 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 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 ac2160ecb4ae1..c77c86711abf0 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 ef9ba19fbb435..0000000000000 --- 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 { - - 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 c90e6b1360dfc..e3037543f2e37 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -289,6 +289,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 9be2d124026ca..dffad6ccbea55 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 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 0000000000000..560b159485914 --- /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 a867825e223d3..854be1f767221 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()); } From 9408c9089afba9f4125a2eff6e3707a8f404469c Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Wed, 23 Sep 2020 14:01:33 +0000 Subject: [PATCH 2/7] Revert^2 "5/N Add KeyguardSecurityViewFlipperController." 612c5d78c418ff33b36a19a7911e4279a26bcf9b Change-Id: Ic51f3c2dd7d49832927393df9831d956bfa45763 --- .../keyguard/KeyguardHostViewController.java | 4 +- .../keyguard/KeyguardInputViewController.java | 6 +- .../keyguard/KeyguardSecurityContainer.java | 8 - .../KeyguardSecurityContainerController.java | 125 ++++-------- ...KeyguardSecurityViewFlipperController.java | 186 ++++++++++++++++++ .../dagger/KeyguardBouncerModule.java | 11 +- ...yguardSecurityContainerControllerTest.java | 59 ++---- ...uardSecurityViewFlipperControllerTest.java | 107 ++++++++++ 8 files changed, 366 insertions(+), 140 deletions(-) create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java create mode 100644 packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java index b0a5533b0745a..ad6ca8582bf08 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 } public SecurityMode getCurrentSecurityMode() { - return mKeyguardSecurityContainerController.getCurrentSecuritySelection(); + return mKeyguardSecurityContainerController.getCurrentSecurityMode(); } public int getTop() { @@ -350,7 +350,7 @@ public class KeyguardHostViewController extends ViewController } public boolean handleBackKey() { - if (mKeyguardSecurityContainerController.getCurrentSecuritySelection() + if (mKeyguardSecurityContainerController.getCurrentSecurityMode() != SecurityMode.None) { mKeyguardSecurityContainerController.dismiss( false, KeyguardUpdateMonitor.getCurrentUser()); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index b0b2cd8c74d97..83fcac6579f26 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -136,9 +136,9 @@ public class KeyguardInputViewController extends ViewController implements KeyguardSecurityView { @@ -70,13 +70,11 @@ public class KeyguardSecurityContainerController extends ViewController mChildren = new ArrayList<>(); private SecurityCallback mSecurityCallback; - private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid; - private KeyguardSecurityView mCurrentSecurityView; + private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid; private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() { public void userActivity() { @@ -182,9 +180,7 @@ public class KeyguardSecurityContainerController extends ViewController implements KeyguardSecurityView { + + private static final boolean DEBUG = KeyguardConstants.DEBUG; + private static final String TAG = "KeyguardSecurityView"; + + private final List mChildren = new ArrayList<>(); + private final LayoutInflater mLayoutInflater; + private final Factory mKeyguardSecurityViewControllerFactory; + + @Inject + protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view, + LayoutInflater layoutInflater, + InjectionInflationController injectionInflationController, + KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory) { + super(view); + mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; + mLayoutInflater = injectionInflationController.injectable(layoutInflater); + } + + @Override + protected void onViewAttached() { + + } + + @Override + protected void onViewDetached() { + + } + + @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(); + } + + @VisibleForTesting + KeyguardInputViewController getSecurityView(SecurityMode securityMode, + KeyguardSecurityCallback keyguardSecurityCallback) { + 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, false); + mView.addView(view); + childController = mKeyguardSecurityViewControllerFactory.create( + view, securityMode, keyguardSecurityCallback); + + 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; + } + } + + /** Makes the supplied child visible if it is contained win this view, */ + public void show(KeyguardInputViewController childController) { + int index = childController.getIndexIn(mView); + if (index != -1) { + mView.setDisplayedChild(index); + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java index b6010c8915e7c..881108858b517 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java @@ -22,6 +22,7 @@ import android.view.ViewGroup; import com.android.keyguard.KeyguardHostView; import com.android.keyguard.KeyguardMessageArea; import com.android.keyguard.KeyguardSecurityContainer; +import com.android.keyguard.KeyguardSecurityViewFlipper; import com.android.systemui.R; import com.android.systemui.statusbar.phone.KeyguardBouncer; @@ -58,7 +59,15 @@ public interface KeyguardBouncerModule { /** */ @Provides @KeyguardBouncerScope - static KeyguardSecurityContainer preovidesKeyguardSecurityContainer(KeyguardHostView hostView) { + static KeyguardSecurityContainer providesKeyguardSecurityContainer(KeyguardHostView hostView) { return hostView.findViewById(R.id.keyguard_security_container); } + + /** */ + @Provides + @KeyguardBouncerScope + static KeyguardSecurityViewFlipper providesKeyguardSecurityViewFlipper( + KeyguardSecurityContainer containerView) { + return containerView.findViewById(R.id.view_flipper); + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index 560b159485914..cdb91ecfad899 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -17,18 +17,14 @@ 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; @@ -39,7 +35,6 @@ 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; @@ -76,21 +71,15 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @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; + private KeyguardInputViewController mInputViewController; @Mock private KeyguardSecurityContainer.SecurityCallback mSecurityCallback; @Mock private WindowInsetsController mWindowInsetsController; @Mock private KeyguardSecurityViewFlipper mSecurityViewFlipper; + @Mock + private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController; private KeyguardSecurityContainerController mKeyguardSecurityContainerController; @@ -98,39 +87,28 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { 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 - ); + mKeyguardStateController, mKeyguardSecurityViewFlipperController); 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); + SecurityMode[] modes = SecurityMode.values(); + for (SecurityMode mode : modes) { + when(mInputViewController.getSecurityMode()).thenReturn(mode); mKeyguardSecurityContainerController.showSecurityScreen(mode); - if (mode == SecurityMode.Invalid || mode == SecurityMode.None) { - verify(mLayoutInflater, never()).inflate( - anyInt(), any(ViewGroup.class), anyBoolean()); + if (mode == SecurityMode.Invalid) { + verify(mKeyguardSecurityViewFlipperController, never()).getSecurityView( + any(SecurityMode.class), any(KeyguardSecurityCallback.class)); } else { - verify(mLayoutInflater).inflate(anyInt(), eq(mSecurityViewFlipper), eq(false)); + verify(mKeyguardSecurityViewFlipperController).getSecurityView( + eq(mode), any(KeyguardSecurityCallback.class)); } } } @@ -138,14 +116,15 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @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); + SecurityMode.Password); + when(mInputViewController.getSecurityMode()).thenReturn( + SecurityMode.Password); + when(mKeyguardSecurityViewFlipperController.getSecurityView( + eq(SecurityMode.Password), any(KeyguardSecurityCallback.class))) + .thenReturn(mInputViewController); mKeyguardSecurityContainerController.showPrimarySecurityScreen(false /* turningOff */); mKeyguardSecurityContainerController.startDisappearAnimation(null); - verify(mKeyguardInputViewController).startDisappearAnimation(eq(null)); + verify(mInputViewController).startDisappearAnimation(eq(null)); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java new file mode 100644 index 0000000000000..5061eedf453a8 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java @@ -0,0 +1,107 @@ +/* + * 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.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.SysuiTestCase; +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 KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { + + @Rule + public MockitoRule mRule = MockitoJUnit.rule(); + + @Mock + private KeyguardSecurityViewFlipper mView; + @Mock + private LayoutInflater mLayoutInflater; + @Mock + private InjectionInflationController mInjectionInflationController; + @Mock + private KeyguardInputViewController.Factory mKeyguardSecurityViewControllerFactory; + @Mock + private KeyguardInputViewController mKeyguardInputViewController; + @Mock + private KeyguardInputView mInputView; + @Mock + private WindowInsetsController mWindowInsetsController; + @Mock + private KeyguardSecurityCallback mKeyguardSecurityCallback; + + private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController; + + @Before + public void setup() { + when(mInjectionInflationController.injectable(mLayoutInflater)).thenReturn(mLayoutInflater); + when(mKeyguardSecurityViewControllerFactory.create( + any(KeyguardInputView.class), any(SecurityMode.class), + any(KeyguardSecurityCallback.class))) + .thenReturn(mKeyguardInputViewController); + when(mView.getWindowInsetsController()).thenReturn(mWindowInsetsController); + + mKeyguardSecurityViewFlipperController = new KeyguardSecurityViewFlipperController(mView, + mLayoutInflater, mInjectionInflationController, + mKeyguardSecurityViewControllerFactory); + } + + @Test + public void showSecurityScreen_canInflateAllModes() { + SecurityMode[] modes = SecurityMode.values(); + // Always return an invalid controller so that we're always making a new one. + when(mKeyguardInputViewController.getSecurityMode()).thenReturn(SecurityMode.Invalid); + for (SecurityMode mode : modes) { + reset(mLayoutInflater); + when(mLayoutInflater.inflate(anyInt(), eq(mView), eq(false))) + .thenReturn(mInputView); + mKeyguardSecurityViewFlipperController.getSecurityView(mode, mKeyguardSecurityCallback); + if (mode == SecurityMode.Invalid || mode == SecurityMode.None) { + verify(mLayoutInflater, never()).inflate( + anyInt(), any(ViewGroup.class), anyBoolean()); + } else { + verify(mLayoutInflater).inflate(anyInt(), eq(mView), eq(false)); + } + } + } +} From 6350a9f10bdb3f72e89122bd16fe29341dd1cd05 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Wed, 23 Sep 2020 14:01:33 +0000 Subject: [PATCH 3/7] Revert^2 "6/N Add Controller for KeyguardPatternView" 87f6d21e679af9f783777d21f08c46f8bcaf04c0 Change-Id: Id01e3ba154a6fe1d73f720b9389920dad60332ac --- .../keyguard/KeyguardInputViewController.java | 26 +- .../KeyguardMessageAreaController.java | 20 +- .../android/keyguard/KeyguardPatternView.java | 295 +-------------- .../KeyguardPatternViewController.java | 344 ++++++++++++++++++ .../KeyguardSecurityContainerController.java | 1 + ...KeyguardSecurityViewFlipperController.java | 5 +- .../KeyguardPatternViewControllerTest.kt | 84 +++++ .../keyguard/KeyguardPatternViewTest.kt | 59 --- 8 files changed, 485 insertions(+), 349 deletions(-) create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java create mode 100644 packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt delete mode 100644 packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index 83fcac6579f26..552e62052e6f0 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -19,6 +19,7 @@ package com.android.keyguard; import android.content.res.ColorStateList; import android.view.MotionEvent; +import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.util.ViewController; @@ -27,18 +28,21 @@ import javax.inject.Inject; /** Controller for a {@link KeyguardSecurityView}. */ -public class KeyguardInputViewController extends ViewController +public class KeyguardInputViewController extends ViewController implements KeyguardSecurityView { private final SecurityMode mSecurityMode; private final LockPatternUtils mLockPatternUtils; + private final KeyguardSecurityCallback mKeyguardSecurityCallback; + private KeyguardMessageAreaController mMessageAreaController; - private KeyguardInputViewController(KeyguardInputView view, SecurityMode securityMode, + protected KeyguardInputViewController(T view, SecurityMode securityMode, LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback) { super(view); mSecurityMode = securityMode; mLockPatternUtils = lockPatternUtils; + mKeyguardSecurityCallback = keyguardSecurityCallback; mView.setKeyguardCallback(keyguardSecurityCallback); } @@ -143,17 +147,31 @@ public class KeyguardInputViewController extends ViewController(keyguardInputView, securityMode, mLockPatternUtils, keyguardSecurityCallback); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java index f056bdbb97065..78ac4e48501be 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java @@ -16,6 +16,8 @@ package com.android.keyguard; +import android.content.res.ColorStateList; + import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.ViewController; @@ -37,17 +39,25 @@ public class KeyguardMessageAreaController extends ViewController, - EmergencyButton.EmergencyButtonCallback { + implements AppearAnimationCreator { private static final String TAG = "SecurityPatternView"; private static final boolean DEBUG = KeyguardConstants.DEBUG; - // how long before we clear the wrong pattern - private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000; // how long we stay awake after each key beyond MIN_PATTERN_BEFORE_POKE_WAKELOCK private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000; - // how many cells the user has to cross before we poke the wakelock - private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2; - // How much we scale up the duration of the disappear animation when the current user is locked public static final float DISAPPEAR_MULTIPLIER_LOCKED = 1.5f; // Extra padding, in pixels, that should eat touch events. private static final int PATTERNS_TOUCH_AREA_EXTENSION = 40; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final AppearAnimationUtils mAppearAnimationUtils; private final DisappearAnimationUtils mDisappearAnimationUtils; private final DisappearAnimationUtils mDisappearAnimationUtilsLocked; @@ -77,9 +57,6 @@ public class KeyguardPatternView extends KeyguardInputView private final Rect mTempRect = new Rect(); private final Rect mLockPatternScreenBounds = new Rect(); - private CountDownTimer mCountdownTimer = null; - private LockPatternUtils mLockPatternUtils; - private AsyncTask mPendingLockCheck; private LockPatternView mLockPatternView; private KeyguardSecurityCallback mCallback; @@ -91,34 +68,17 @@ public class KeyguardPatternView extends KeyguardInputView */ private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS; - /** - * Useful for clearing out the wrong pattern after a delay - */ - private Runnable mCancelPatternRunnable = new Runnable() { - @Override - public void run() { - mLockPatternView.clearPattern(); - } - }; - @VisibleForTesting KeyguardMessageArea mSecurityMessageDisplay; private View mEcaView; private ViewGroup mContainer; private int mDisappearYTranslation; - enum FooterMode { - Normal, - ForgotLockPattern, - VerifyUnlocked - } - public KeyguardPatternView(Context context) { this(context, null); } public KeyguardPatternView(Context context, AttributeSet attrs) { super(context, attrs); - mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); mAppearAnimationUtils = new AppearAnimationUtils(context, AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 1.5f /* translationScale */, 2.0f /* delayScale */, AnimationUtils.loadInterpolator( @@ -142,39 +102,16 @@ public class KeyguardPatternView extends KeyguardInputView @Override public void setLockPatternUtils(LockPatternUtils utils) { - mLockPatternUtils = utils; } @Override protected void onFinishInflate() { super.onFinishInflate(); - mLockPatternUtils = mLockPatternUtils == null - ? new LockPatternUtils(mContext) : mLockPatternUtils; mLockPatternView = findViewById(R.id.lockPatternView); - mLockPatternView.setSaveEnabled(false); - mLockPatternView.setOnPatternListener(new UnlockPatternListener()); - mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled( - KeyguardUpdateMonitor.getCurrentUser())); - - // vibrate mode will be the same for the life of this screen - mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); mEcaView = findViewById(R.id.keyguard_selector_fade_container); mContainer = findViewById(R.id.container); - - EmergencyButton button = findViewById(R.id.emergency_call_button); - if (button != null) { - button.setCallback(this); - } - - View cancelBtn = findViewById(R.id.cancel_button); - if (cancelBtn != null) { - cancelBtn.setOnClickListener(view -> { - mCallback.reset(); - mCallback.onCancelClicked(); - }); - } } @Override @@ -183,11 +120,6 @@ public class KeyguardPatternView extends KeyguardInputView mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this); } - @Override - public void onEmergencyButtonClickedWhenInCall() { - mCallback.reset(); - } - @Override public boolean onTouchEvent(MotionEvent ev) { boolean result = super.onTouchEvent(ev); @@ -217,31 +149,6 @@ public class KeyguardPatternView extends KeyguardInputView @Override public void reset() { - // reset lock pattern - mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled( - KeyguardUpdateMonitor.getCurrentUser())); - mLockPatternView.enableInput(); - mLockPatternView.setEnabled(true); - mLockPatternView.clearPattern(); - - if (mSecurityMessageDisplay == null) { - return; - } - - // if the user is currently locked out, enforce it. - long deadline = mLockPatternUtils.getLockoutAttemptDeadline( - KeyguardUpdateMonitor.getCurrentUser()); - if (deadline != 0) { - handleAttemptLockout(deadline); - } else { - displayDefaultSecurityMessage(); - } - } - - private void displayDefaultSecurityMessage() { - if (mSecurityMessageDisplay != null) { - mSecurityMessageDisplay.setMessage(""); - } } @Override @@ -254,148 +161,6 @@ public class KeyguardPatternView extends KeyguardInputView || mLockPatternScreenBounds.contains((int) event.getRawX(), (int) event.getRawY()); } - /** TODO: hook this up */ - public void cleanUp() { - if (DEBUG) Log.v(TAG, "Cleanup() called on " + this); - mLockPatternUtils = null; - mLockPatternView.setOnPatternListener(null); - } - - private class UnlockPatternListener implements LockPatternView.OnPatternListener { - - @Override - public void onPatternStart() { - mLockPatternView.removeCallbacks(mCancelPatternRunnable); - mSecurityMessageDisplay.setMessage(""); - } - - @Override - public void onPatternCleared() { - } - - @Override - public void onPatternCellAdded(List pattern) { - mCallback.userActivity(); - mCallback.onUserInput(); - } - - @Override - public void onPatternDetected(final List pattern) { - mKeyguardUpdateMonitor.setCredentialAttempted(); - mLockPatternView.disableInput(); - if (mPendingLockCheck != null) { - mPendingLockCheck.cancel(false); - } - - final int userId = KeyguardUpdateMonitor.getCurrentUser(); - if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { - mLockPatternView.enableInput(); - onPatternChecked(userId, false, 0, false /* not valid - too short */); - return; - } - - if (LatencyTracker.isEnabled(mContext)) { - LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL); - LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED); - } - mPendingLockCheck = LockPatternChecker.checkCredential( - mLockPatternUtils, - LockscreenCredential.createPattern(pattern), - userId, - new LockPatternChecker.OnCheckCallback() { - - @Override - public void onEarlyMatched() { - if (LatencyTracker.isEnabled(mContext)) { - LatencyTracker.getInstance(mContext).onActionEnd( - ACTION_CHECK_CREDENTIAL); - } - onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */, - true /* isValidPattern */); - } - - @Override - public void onChecked(boolean matched, int timeoutMs) { - if (LatencyTracker.isEnabled(mContext)) { - LatencyTracker.getInstance(mContext).onActionEnd( - ACTION_CHECK_CREDENTIAL_UNLOCKED); - } - mLockPatternView.enableInput(); - mPendingLockCheck = null; - if (!matched) { - onPatternChecked(userId, false /* matched */, timeoutMs, - true /* isValidPattern */); - } - } - - @Override - public void onCancelled() { - // We already got dismissed with the early matched callback, so we - // cancelled the check. However, we still need to note down the latency. - if (LatencyTracker.isEnabled(mContext)) { - LatencyTracker.getInstance(mContext).onActionEnd( - ACTION_CHECK_CREDENTIAL_UNLOCKED); - } - } - }); - if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { - mCallback.userActivity(); - mCallback.onUserInput(); - } - } - - private void onPatternChecked(int userId, boolean matched, int timeoutMs, - boolean isValidPattern) { - boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId; - if (matched) { - mCallback.reportUnlockAttempt(userId, true, 0); - if (dismissKeyguard) { - mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct); - mCallback.dismiss(true, userId); - } - } else { - mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); - if (isValidPattern) { - mCallback.reportUnlockAttempt(userId, false, timeoutMs); - if (timeoutMs > 0) { - long deadline = mLockPatternUtils.setLockoutAttemptDeadline( - userId, timeoutMs); - handleAttemptLockout(deadline); - } - } - if (timeoutMs == 0) { - mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern); - mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS); - } - } - } - } - - private void handleAttemptLockout(long elapsedRealtimeDeadline) { - mLockPatternView.clearPattern(); - mLockPatternView.setEnabled(false); - final long elapsedRealtime = SystemClock.elapsedRealtime(); - final long secondsInFuture = (long) Math.ceil( - (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0); - mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) { - - @Override - public void onTick(long millisUntilFinished) { - final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0); - mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString( - R.plurals.kg_too_many_failed_attempts_countdown, - secondsRemaining, secondsRemaining)); - } - - @Override - public void onFinish() { - mLockPatternView.setEnabled(true); - displayDefaultSecurityMessage(); - } - - }.start(); - } - @Override public boolean needsInput() { return false; @@ -403,15 +168,6 @@ public class KeyguardPatternView extends KeyguardInputView @Override public void onPause() { - if (mCountdownTimer != null) { - mCountdownTimer.cancel(); - mCountdownTimer = null; - } - if (mPendingLockCheck != null) { - mPendingLockCheck.cancel(false); - mPendingLockCheck = null; - } - displayDefaultSecurityMessage(); } @Override @@ -425,36 +181,10 @@ public class KeyguardPatternView extends KeyguardInputView @Override public void showPromptReason(int reason) { - switch (reason) { - case PROMPT_REASON_RESTART: - mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_restart_pattern); - break; - case PROMPT_REASON_TIMEOUT: - mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern); - break; - case PROMPT_REASON_DEVICE_ADMIN: - mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_device_admin); - break; - case PROMPT_REASON_USER_REQUEST: - mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_user_request); - break; - case PROMPT_REASON_PREPARE_FOR_UPDATE: - mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern); - break; - case PROMPT_REASON_NONE: - break; - default: - mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern); - break; - } } @Override public void showMessage(CharSequence message, ColorStateList colorState) { - if (colorState != null) { - mSecurityMessageDisplay.setNextMessageColor(colorState); - } - mSecurityMessageDisplay.setMessage(message); } @Override @@ -483,11 +213,18 @@ public class KeyguardPatternView extends KeyguardInputView } } + /** + * @deprecated Use {@link #startDisappearAnimation(boolean, Runnable)} + */ @Override - public boolean startDisappearAnimation(final Runnable finishRunnable) { - float durationMultiplier = mKeyguardUpdateMonitor.needsSlowUnlockTransition() - ? DISAPPEAR_MULTIPLIER_LOCKED - : 1f; + public boolean startDisappearAnimation(Runnable finishRunnable) { + // TODO(b/166448040): remove this when possible + return false; + } + + public boolean startDisappearAnimation(boolean needsSlowUnlockTransition, + final Runnable finishRunnable) { + float durationMultiplier = needsSlowUnlockTransition ? DISAPPEAR_MULTIPLIER_LOCKED : 1f; mLockPatternView.clearPattern(); enableClipping(false); setTranslationY(0); @@ -496,10 +233,8 @@ public class KeyguardPatternView extends KeyguardInputView -mDisappearAnimationUtils.getStartTranslation(), mDisappearAnimationUtils.getInterpolator()); - DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor - .needsSlowUnlockTransition() - ? mDisappearAnimationUtilsLocked - : mDisappearAnimationUtils; + DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition + ? mDisappearAnimationUtilsLocked : mDisappearAnimationUtils; disappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(), () -> { enableClipping(true); @@ -548,7 +283,7 @@ public class KeyguardPatternView extends KeyguardInputView @Override public CharSequence getTitle() { - return getContext().getString( + return getResources().getString( com.android.internal.R.string.keyguard_accessibility_pattern_unlock); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java new file mode 100644 index 0000000000000..5e547d3120bfe --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -0,0 +1,344 @@ +/* + * 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 com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL; +import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED; + +import android.content.res.ColorStateList; +import android.os.AsyncTask; +import android.os.CountDownTimer; +import android.os.SystemClock; +import android.view.View; + +import com.android.internal.util.LatencyTracker; +import com.android.internal.widget.LockPatternChecker; +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockPatternView; +import com.android.internal.widget.LockPatternView.Cell; +import com.android.internal.widget.LockscreenCredential; +import com.android.keyguard.EmergencyButton.EmergencyButtonCallback; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; + +import java.util.List; + +public class KeyguardPatternViewController + extends KeyguardInputViewController { + + // how many cells the user has to cross before we poke the wakelock + private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2; + + // how long before we clear the wrong pattern + private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000; + + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final LockPatternUtils mLockPatternUtils; + private final LatencyTracker mLatencyTracker; + private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory; + + private KeyguardMessageAreaController mMessageAreaController; + private LockPatternView mLockPatternView; + private CountDownTimer mCountdownTimer; + private KeyguardSecurityCallback mCallback; + private AsyncTask mPendingLockCheck; + + private EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() { + @Override + public void onEmergencyButtonClickedWhenInCall() { + mCallback.reset(); + } + }; + + /** + * Useful for clearing out the wrong pattern after a delay + */ + private Runnable mCancelPatternRunnable = new Runnable() { + @Override + public void run() { + mLockPatternView.clearPattern(); + } + }; + + private class UnlockPatternListener implements LockPatternView.OnPatternListener { + + @Override + public void onPatternStart() { + mLockPatternView.removeCallbacks(mCancelPatternRunnable); + mMessageAreaController.setMessage(""); + } + + @Override + public void onPatternCleared() { + } + + @Override + public void onPatternCellAdded(List pattern) { + mCallback.userActivity(); + mCallback.onUserInput(); + } + + @Override + public void onPatternDetected(final List pattern) { + mKeyguardUpdateMonitor.setCredentialAttempted(); + mLockPatternView.disableInput(); + if (mPendingLockCheck != null) { + mPendingLockCheck.cancel(false); + } + + final int userId = KeyguardUpdateMonitor.getCurrentUser(); + if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { + mLockPatternView.enableInput(); + onPatternChecked(userId, false, 0, false /* not valid - too short */); + return; + } + + mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL); + mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED); + mPendingLockCheck = LockPatternChecker.checkCredential( + mLockPatternUtils, + LockscreenCredential.createPattern(pattern), + userId, + new LockPatternChecker.OnCheckCallback() { + + @Override + public void onEarlyMatched() { + mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL); + onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */, + true /* isValidPattern */); + } + + @Override + public void onChecked(boolean matched, int timeoutMs) { + mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED); + mLockPatternView.enableInput(); + mPendingLockCheck = null; + if (!matched) { + onPatternChecked(userId, false /* matched */, timeoutMs, + true /* isValidPattern */); + } + } + + @Override + public void onCancelled() { + // We already got dismissed with the early matched callback, so we + // cancelled the check. However, we still need to note down the latency. + mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED); + } + }); + if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { + mCallback.userActivity(); + mCallback.onUserInput(); + } + } + + private void onPatternChecked(int userId, boolean matched, int timeoutMs, + boolean isValidPattern) { + boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId; + if (matched) { + mCallback.reportUnlockAttempt(userId, true, 0); + if (dismissKeyguard) { + mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct); + mCallback.dismiss(true, userId); + } + } else { + mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); + if (isValidPattern) { + mCallback.reportUnlockAttempt(userId, false, timeoutMs); + if (timeoutMs > 0) { + long deadline = mLockPatternUtils.setLockoutAttemptDeadline( + userId, timeoutMs); + handleAttemptLockout(deadline); + } + } + if (timeoutMs == 0) { + mMessageAreaController.setMessage(R.string.kg_wrong_pattern); + mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS); + } + } + } + } + + protected KeyguardPatternViewController(KeyguardPatternView view, + KeyguardUpdateMonitor keyguardUpdateMonitor, + SecurityMode securityMode, + LockPatternUtils lockPatternUtils, + KeyguardSecurityCallback keyguardSecurityCallback, + LatencyTracker latencyTracker, + KeyguardMessageAreaController.Factory messageAreaControllerFactory) { + super(view, securityMode, lockPatternUtils, keyguardSecurityCallback); + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mLockPatternUtils = lockPatternUtils; + mLatencyTracker = latencyTracker; + mMessageAreaControllerFactory = messageAreaControllerFactory; + } + + @Override + protected void onViewAttached() { + KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView); + mMessageAreaController = mMessageAreaControllerFactory.create(kma); + mLockPatternView = mView.findViewById(R.id.lockPatternView); + mLockPatternView.setOnPatternListener(new UnlockPatternListener()); + mLockPatternView.setSaveEnabled(false); + mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled( + KeyguardUpdateMonitor.getCurrentUser())); + // vibrate mode will be the same for the life of this screen + mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); + + EmergencyButton button = mView.findViewById(R.id.emergency_call_button); + if (button != null) { + button.setCallback(mEmergencyButtonCallback); + } + + View cancelBtn = mView.findViewById(R.id.cancel_button); + if (cancelBtn != null) { + cancelBtn.setOnClickListener(view -> { + mCallback.reset(); + mCallback.onCancelClicked(); + }); + } + } + + @Override + protected void onViewDetached() { + super.onViewDetached(); + mLockPatternView.setOnPatternListener(null); + EmergencyButton button = mView.findViewById(R.id.emergency_call_button); + if (button != null) { + button.setCallback(null); + } + View cancelBtn = mView.findViewById(R.id.cancel_button); + if (cancelBtn != null) { + cancelBtn.setOnClickListener(null); + } + } + + @Override + public void reset() { + // reset lock pattern + mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled( + KeyguardUpdateMonitor.getCurrentUser())); + mLockPatternView.enableInput(); + mLockPatternView.setEnabled(true); + mLockPatternView.clearPattern(); + + // if the user is currently locked out, enforce it. + long deadline = mLockPatternUtils.getLockoutAttemptDeadline( + KeyguardUpdateMonitor.getCurrentUser()); + if (deadline != 0) { + handleAttemptLockout(deadline); + } else { + displayDefaultSecurityMessage(); + } + } + + @Override + public void onPause() { + super.onPause(); + + if (mCountdownTimer != null) { + mCountdownTimer.cancel(); + mCountdownTimer = null; + } + + if (mPendingLockCheck != null) { + mPendingLockCheck.cancel(false); + mPendingLockCheck = null; + } + displayDefaultSecurityMessage(); + } + + @Override + public void setKeyguardCallback(KeyguardSecurityCallback callback) { + mCallback = callback; + } + + @Override + public void showPromptReason(int reason) { + /// TODO: move all this logic into the MessageAreaController? + switch (reason) { + case PROMPT_REASON_RESTART: + mMessageAreaController.setMessage(R.string.kg_prompt_reason_restart_pattern); + break; + case PROMPT_REASON_TIMEOUT: + mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern); + break; + case PROMPT_REASON_DEVICE_ADMIN: + mMessageAreaController.setMessage(R.string.kg_prompt_reason_device_admin); + break; + case PROMPT_REASON_USER_REQUEST: + mMessageAreaController.setMessage(R.string.kg_prompt_reason_user_request); + break; + case PROMPT_REASON_PREPARE_FOR_UPDATE: + mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern); + break; + case PROMPT_REASON_NONE: + break; + default: + mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern); + break; + } + } + + @Override + public void showMessage(CharSequence message, ColorStateList colorState) { + if (colorState != null) { + mMessageAreaController.setNextMessageColor(colorState); + } + mMessageAreaController.setMessage(message); + } + + @Override + public void startAppearAnimation() { + super.startAppearAnimation(); + } + + @Override + public boolean startDisappearAnimation(Runnable finishRunnable) { + return mView.startDisappearAnimation( + mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable); + } + + private void displayDefaultSecurityMessage() { + mMessageAreaController.setMessage(""); + } + + private void handleAttemptLockout(long elapsedRealtimeDeadline) { + mLockPatternView.clearPattern(); + mLockPatternView.setEnabled(false); + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long secondsInFuture = (long) Math.ceil( + (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0); + mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) { + + @Override + public void onTick(long millisUntilFinished) { + final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0); + mMessageAreaController.setMessage(mView.getResources().getQuantityString( + R.plurals.kg_too_many_failed_attempts_countdown, + secondsRemaining, secondsRemaining)); + } + + @Override + public void onFinish() { + mLockPatternView.setEnabled(true); + displayDefaultSecurityMessage(); + } + + }.start(); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 87d3dd8182322..342f3de2ede31 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -256,6 +256,7 @@ public class KeyguardSecurityContainerController extends ViewController(R.id.keyguard_message_area)) + .thenReturn(mKeyguardMessageArea) + `when`(mKeyguardPatternView.findViewById(R.id.lockPatternView)) + .thenReturn(mLockPatternView) + `when`(mKeyguardMessageAreaControllerFactory.create(mKeyguardMessageArea)) + .thenReturn(mKeyguardMessageAreaController) + mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView, + mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, + mLatencyTracker, mKeyguardMessageAreaControllerFactory) + } + + @Test + fun onPause_clearsTextField() { + mKeyguardPatternViewController.init() + mKeyguardPatternViewController.onPause() + verify(mKeyguardMessageAreaController).setMessage("") + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt deleted file mode 100644 index b4363cf215f1a..0000000000000 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2018 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 androidx.test.filters.SmallTest -import android.testing.AndroidTestingRunner -import android.testing.TestableLooper -import android.view.LayoutInflater - -import com.android.systemui.R -import com.android.systemui.SysuiTestCase -import com.android.systemui.statusbar.policy.ConfigurationController -import com.google.common.truth.Truth.assertThat - -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mockito.mock - -@SmallTest -@RunWith(AndroidTestingRunner::class) -@TestableLooper.RunWithLooper -class KeyguardPatternViewTest : SysuiTestCase() { - - private lateinit var mKeyguardPatternView: KeyguardPatternView - private lateinit var mSecurityMessage: KeyguardMessageArea - - @Before - fun setup() { - val inflater = LayoutInflater.from(context) - mDependency.injectMockDependency(KeyguardUpdateMonitor::class.java) - mKeyguardPatternView = inflater.inflate(R.layout.keyguard_pattern_view, null) - as KeyguardPatternView - mSecurityMessage = KeyguardMessageArea(mContext, null, - mock(KeyguardUpdateMonitor::class.java), mock(ConfigurationController::class.java)) - mKeyguardPatternView.mSecurityMessageDisplay = mSecurityMessage - } - - @Test - fun onPause_clearsTextField() { - mSecurityMessage.setMessage("an old message") - mKeyguardPatternView.onPause() - assertThat(mSecurityMessage.text).isEqualTo("") - } -} From dc0193004485c8a2700ecd78fc2a907df6bd03ee Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Wed, 23 Sep 2020 14:01:33 +0000 Subject: [PATCH 4/7] Revert^2 "7/N controllers for remaining Keyguard Password ..." Revert submission 12656261-revert-12585643-b166448040-keyguard-message-area-NUUJOVRYJS This also fixes the original issue introduced in this CL. KeyguardAbsKeyInputViewController#reset would call mView#resetState instead of its own internal resetState method. However, all the logic from the various resetState methods had been moved from the views to their controllers. Simply calling resetState direclty resolves the issue (line 105 of KeyguardAbsKeyInputViewController). Reason for revert: Fixing http://b/169231892 and http://b/169145796 Reverted Changes: I7683b2234:Revert "4/N Setup Controller fo KeyguardSecurityCo... I5cbe04c0c:Revert "5/N Add KeyguardSecurityViewFlipperControl... I11dff38ad:Revert "6/N Add Controller for KeyguardPatternView... I55c250121:Revert "7/N controllers for remaining Keyguard Pas... Ie84234cb8:Revert "8/N Remove View Injection from KeyguardMes... Ic62f199a5:Revert "9/N Clean Up Keyguard Class Structure" Change-Id: Ie3669e0c9a23ffd4443ced0fb08ec754f1df55db Fixes: 169145796 --- .../keyguard/KeyguardAbsKeyInputView.java | 229 +--------- .../KeyguardAbsKeyInputViewController.java | 257 +++++++++++ .../keyguard/KeyguardHostViewController.java | 10 +- .../keyguard/KeyguardInputViewController.java | 54 ++- .../com/android/keyguard/KeyguardPINView.java | 39 +- .../keyguard/KeyguardPasswordView.java | 235 +--------- .../KeyguardPasswordViewController.java | 270 ++++++++++++ .../KeyguardPatternViewController.java | 8 +- .../keyguard/KeyguardPinBasedInputView.java | 140 +----- .../KeyguardPinBasedInputViewController.java | 113 +++++ .../keyguard/KeyguardPinViewController.java | 50 +++ .../KeyguardSecurityContainerController.java | 1 + .../android/keyguard/KeyguardSimPinView.java | 310 +------------- .../KeyguardSimPinViewController.java | 350 +++++++++++++++ .../android/keyguard/KeyguardSimPukView.java | 376 +--------------- .../KeyguardSimPukViewController.java | 404 ++++++++++++++++++ .../keyguard/LiftToActivateListener.java | 9 +- .../src/com/android/keyguard/NumPadKey.java | 4 +- .../dagger/FrameworkServicesModule.java | 7 + .../android/systemui/util/ViewController.java | 15 +- ...KeyguardAbsKeyInputViewControllerTest.java | 120 ++++++ ...yguardPinBasedInputViewControllerTest.java | 106 +++++ .../KeyguardPinBasedInputViewTest.java | 79 ---- 23 files changed, 1830 insertions(+), 1356 deletions(-) create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java create mode 100644 packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java create mode 100644 packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java index 889309dd72e72..1296990d49314 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -16,45 +16,30 @@ package com.android.keyguard; -import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL; -import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED; - import android.content.Context; import android.content.res.ColorStateList; -import android.os.AsyncTask; -import android.os.CountDownTimer; -import android.os.SystemClock; import android.util.AttributeSet; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.View; -import com.android.internal.util.LatencyTracker; -import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; -import com.android.systemui.Dependency; 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 KeyguardInputView { protected KeyguardSecurityCallback mCallback; - protected LockPatternUtils mLockPatternUtils; - protected AsyncTask mPendingLockCheck; protected SecurityMessageDisplay mSecurityMessageDisplay; protected View mEcaView; protected boolean mEnableHaptics; - private boolean mDismissing; - protected boolean mResumed; - private CountDownTimer mCountdownTimer = null; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; // To avoid accidental lockout due to events while the device in in the pocket, ignore // any passwords with length less than or equal to this length. protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3; + private KeyDownListener mKeyDownListener; public KeyguardAbsKeyInputView(Context context) { this(context, null); @@ -62,7 +47,10 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) { super(context, attrs); - mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); + } + + void setEnableHaptics(boolean enableHaptics) { + mEnableHaptics = enableHaptics; } @Override @@ -72,28 +60,10 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView @Override public void setLockPatternUtils(LockPatternUtils utils) { - mLockPatternUtils = utils; - mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled(); } @Override public void reset() { - // start fresh - mDismissing = false; - resetPasswordText(false /* animate */, false /* announce */); - // if the user is currently locked out, enforce it. - long deadline = mLockPatternUtils.getLockoutAttemptDeadline( - KeyguardUpdateMonitor.getCurrentUser()); - if (shouldLockout(deadline)) { - handleAttemptLockout(deadline); - } else { - resetState(); - } - } - - // Allow subclasses to override this behavior - protected boolean shouldLockout(long deadline) { - return deadline != 0; } protected abstract int getPasswordTextViewId(); @@ -101,24 +71,7 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView @Override protected void onFinishInflate() { - mLockPatternUtils = new LockPatternUtils(mContext); mEcaView = findViewById(R.id.keyguard_selector_fade_container); - - EmergencyButton button = findViewById(R.id.emergency_call_button); - if (button != null) { - button.setCallback(this); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this); - } - - @Override - public void onEmergencyButtonClickedWhenInCall() { - mCallback.reset(); } /* @@ -130,147 +83,14 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView return R.string.kg_wrong_password; } - protected void verifyPasswordAndUnlock() { - if (mDismissing) return; // already verified but haven't been dismissed; don't do it again. - - final LockscreenCredential password = getEnteredCredential(); - setPasswordEntryInputEnabled(false); - if (mPendingLockCheck != null) { - mPendingLockCheck.cancel(false); - } - - final int userId = KeyguardUpdateMonitor.getCurrentUser(); - if (password.size() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) { - // to avoid accidental lockout, only count attempts that are long enough to be a - // real password. This may require some tweaking. - setPasswordEntryInputEnabled(true); - onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */); - password.zeroize(); - return; - } - - if (LatencyTracker.isEnabled(mContext)) { - LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL); - LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED); - } - - mKeyguardUpdateMonitor.setCredentialAttempted(); - mPendingLockCheck = LockPatternChecker.checkCredential( - mLockPatternUtils, - password, - userId, - new LockPatternChecker.OnCheckCallback() { - - @Override - public void onEarlyMatched() { - if (LatencyTracker.isEnabled(mContext)) { - LatencyTracker.getInstance(mContext).onActionEnd( - ACTION_CHECK_CREDENTIAL); - } - onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */, - true /* isValidPassword */); - password.zeroize(); - } - - @Override - public void onChecked(boolean matched, int timeoutMs) { - if (LatencyTracker.isEnabled(mContext)) { - LatencyTracker.getInstance(mContext).onActionEnd( - ACTION_CHECK_CREDENTIAL_UNLOCKED); - } - setPasswordEntryInputEnabled(true); - mPendingLockCheck = null; - if (!matched) { - onPasswordChecked(userId, false /* matched */, timeoutMs, - true /* isValidPassword */); - } - password.zeroize(); - } - - @Override - public void onCancelled() { - // We already got dismissed with the early matched callback, so we cancelled - // the check. However, we still need to note down the latency. - if (LatencyTracker.isEnabled(mContext)) { - LatencyTracker.getInstance(mContext).onActionEnd( - ACTION_CHECK_CREDENTIAL_UNLOCKED); - } - password.zeroize(); - } - }); - } - - private void onPasswordChecked(int userId, boolean matched, int timeoutMs, - boolean isValidPassword) { - boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId; - if (matched) { - mCallback.reportUnlockAttempt(userId, true, 0); - if (dismissKeyguard) { - mDismissing = true; - mCallback.dismiss(true, userId); - } - } else { - if (isValidPassword) { - mCallback.reportUnlockAttempt(userId, false, timeoutMs); - if (timeoutMs > 0) { - long deadline = mLockPatternUtils.setLockoutAttemptDeadline( - userId, timeoutMs); - handleAttemptLockout(deadline); - } - } - if (timeoutMs == 0) { - mSecurityMessageDisplay.setMessage(getWrongPasswordStringId()); - } - } - resetPasswordText(true /* animate */, !matched /* announce deletion if no match */); - } - protected abstract void resetPasswordText(boolean animate, boolean announce); protected abstract LockscreenCredential getEnteredCredential(); protected abstract void setPasswordEntryEnabled(boolean enabled); protected abstract void setPasswordEntryInputEnabled(boolean enabled); - // Prevent user from using the PIN/Password entry until scheduled deadline. - protected void handleAttemptLockout(long elapsedRealtimeDeadline) { - setPasswordEntryEnabled(false); - long elapsedRealtime = SystemClock.elapsedRealtime(); - long secondsInFuture = (long) Math.ceil( - (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0); - mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) { - - @Override - public void onTick(long millisUntilFinished) { - int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0); - mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString( - R.plurals.kg_too_many_failed_attempts_countdown, - secondsRemaining, secondsRemaining)); - } - - @Override - public void onFinish() { - mSecurityMessageDisplay.setMessage(""); - resetState(); - } - }.start(); - } - - protected void onUserInput() { - if (mCallback != null) { - mCallback.userActivity(); - mCallback.onUserInput(); - } - mSecurityMessageDisplay.setMessage(""); - } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN. - // We don't want to consider it valid user input because the UI - // will already respond to the event. - if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { - onUserInput(); - } - return false; + return mKeyDownListener != null && mKeyDownListener.onKeyDown(keyCode, event); } @Override @@ -278,26 +98,6 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView return false; } - @Override - public void onPause() { - mResumed = false; - - if (mCountdownTimer != null) { - mCountdownTimer.cancel(); - mCountdownTimer = null; - } - if (mPendingLockCheck != null) { - mPendingLockCheck.cancel(false); - mPendingLockCheck = null; - } - reset(); - } - - @Override - public void onResume(int reason) { - mResumed = true; - } - @Override public KeyguardSecurityCallback getCallback() { return mCallback; @@ -305,12 +105,7 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView @Override public void showPromptReason(int reason) { - if (reason != PROMPT_REASON_NONE) { - int promtReasonStringRes = getPromptReasonStringRes(reason); - if (promtReasonStringRes != 0) { - mSecurityMessageDisplay.setMessage(promtReasonStringRes); - } - } + } @Override @@ -336,5 +131,13 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView public boolean startDisappearAnimation(Runnable finishRunnable) { return false; } + + public void setKeyDownListener(KeyDownListener keyDownListener) { + mKeyDownListener = keyDownListener; + } + + public interface KeyDownListener { + boolean onKeyDown(int keyCode, KeyEvent keyEvent); + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java new file mode 100644 index 0000000000000..a33cef3bbd796 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -0,0 +1,257 @@ +/* + * 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 com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL; +import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED; +import static com.android.keyguard.KeyguardAbsKeyInputView.MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT; + +import android.os.AsyncTask; +import android.os.CountDownTimer; +import android.os.SystemClock; +import android.view.KeyEvent; + +import com.android.internal.util.LatencyTracker; +import com.android.internal.widget.LockPatternChecker; +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockscreenCredential; +import com.android.keyguard.EmergencyButton.EmergencyButtonCallback; +import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; + +public abstract class KeyguardAbsKeyInputViewController + extends KeyguardInputViewController { + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final LockPatternUtils mLockPatternUtils; + protected final KeyguardSecurityCallback mKeyguardSecurityCallback; + private final LatencyTracker mLatencyTracker; + private CountDownTimer mCountdownTimer; + protected KeyguardMessageAreaController mMessageAreaController; + private boolean mDismissing; + protected AsyncTask mPendingLockCheck; + protected boolean mResumed; + + private final KeyDownListener mKeyDownListener = (keyCode, keyEvent) -> { + // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN. + // We don't want to consider it valid user input because the UI + // will already respond to the event. + if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { + onUserInput(); + } + return false; + }; + + private final EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() { + @Override + public void onEmergencyButtonClickedWhenInCall() { + mKeyguardSecurityCallback.reset(); + } + }; + + protected KeyguardAbsKeyInputViewController(T view, + KeyguardUpdateMonitor keyguardUpdateMonitor, + SecurityMode securityMode, + LockPatternUtils lockPatternUtils, + KeyguardSecurityCallback keyguardSecurityCallback, + KeyguardMessageAreaController.Factory messageAreaControllerFactory, + LatencyTracker latencyTracker) { + super(view, securityMode, keyguardSecurityCallback); + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mLockPatternUtils = lockPatternUtils; + mKeyguardSecurityCallback = keyguardSecurityCallback; + mLatencyTracker = latencyTracker; + KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView); + mMessageAreaController = messageAreaControllerFactory.create(kma); + } + + abstract void resetState(); + + @Override + protected void onViewAttached() { + mView.setKeyDownListener(mKeyDownListener); + mView.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled()); + EmergencyButton button = mView.findViewById(R.id.emergency_call_button); + if (button != null) { + button.setCallback(mEmergencyButtonCallback); + } + } + + @Override + public void reset() { + // start fresh + mDismissing = false; + mView.resetPasswordText(false /* animate */, false /* announce */); + // if the user is currently locked out, enforce it. + long deadline = mLockPatternUtils.getLockoutAttemptDeadline( + KeyguardUpdateMonitor.getCurrentUser()); + if (shouldLockout(deadline)) { + handleAttemptLockout(deadline); + } else { + resetState(); + } + } + + // Allow subclasses to override this behavior + protected boolean shouldLockout(long deadline) { + return deadline != 0; + } + + // Prevent user from using the PIN/Password entry until scheduled deadline. + protected void handleAttemptLockout(long elapsedRealtimeDeadline) { + mView.setPasswordEntryEnabled(false); + long elapsedRealtime = SystemClock.elapsedRealtime(); + long secondsInFuture = (long) Math.ceil( + (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0); + mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) { + + @Override + public void onTick(long millisUntilFinished) { + int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0); + mMessageAreaController.setMessage(mView.getResources().getQuantityString( + R.plurals.kg_too_many_failed_attempts_countdown, + secondsRemaining, secondsRemaining)); + } + + @Override + public void onFinish() { + mMessageAreaController.setMessage(""); + resetState(); + } + }.start(); + } + + void onPasswordChecked(int userId, boolean matched, int timeoutMs, boolean isValidPassword) { + boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId; + if (matched) { + mKeyguardSecurityCallback.reportUnlockAttempt(userId, true, 0); + if (dismissKeyguard) { + mDismissing = true; + mKeyguardSecurityCallback.dismiss(true, userId); + } + } else { + if (isValidPassword) { + mKeyguardSecurityCallback.reportUnlockAttempt(userId, false, timeoutMs); + if (timeoutMs > 0) { + long deadline = mLockPatternUtils.setLockoutAttemptDeadline( + userId, timeoutMs); + handleAttemptLockout(deadline); + } + } + if (timeoutMs == 0) { + mMessageAreaController.setMessage(mView.getWrongPasswordStringId()); + } + } + mView.resetPasswordText(true /* animate */, !matched /* announce deletion if no match */); + } + + protected void verifyPasswordAndUnlock() { + if (mDismissing) return; // already verified but haven't been dismissed; don't do it again. + + final LockscreenCredential password = mView.getEnteredCredential(); + mView.setPasswordEntryInputEnabled(false); + if (mPendingLockCheck != null) { + mPendingLockCheck.cancel(false); + } + + final int userId = KeyguardUpdateMonitor.getCurrentUser(); + if (password.size() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) { + // to avoid accidental lockout, only count attempts that are long enough to be a + // real password. This may require some tweaking. + mView.setPasswordEntryInputEnabled(true); + onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */); + password.zeroize(); + return; + } + + mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL); + mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED); + + mKeyguardUpdateMonitor.setCredentialAttempted(); + mPendingLockCheck = LockPatternChecker.checkCredential( + mLockPatternUtils, + password, + userId, + new LockPatternChecker.OnCheckCallback() { + + @Override + public void onEarlyMatched() { + mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL); + + onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */, + true /* isValidPassword */); + password.zeroize(); + } + + @Override + public void onChecked(boolean matched, int timeoutMs) { + mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED); + mView.setPasswordEntryInputEnabled(true); + mPendingLockCheck = null; + if (!matched) { + onPasswordChecked(userId, false /* matched */, timeoutMs, + true /* isValidPassword */); + } + password.zeroize(); + } + + @Override + public void onCancelled() { + // We already got dismissed with the early matched callback, so we cancelled + // the check. However, we still need to note down the latency. + mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED); + password.zeroize(); + } + }); + } + + @Override + public void showPromptReason(int reason) { + if (reason != PROMPT_REASON_NONE) { + int promtReasonStringRes = mView.getPromptReasonStringRes(reason); + if (promtReasonStringRes != 0) { + mMessageAreaController.setMessage(promtReasonStringRes); + } + } + } + + protected void onUserInput() { + mKeyguardSecurityCallback.userActivity(); + mKeyguardSecurityCallback.onUserInput(); + mMessageAreaController.setMessage(""); + } + + @Override + public void onResume(int reason) { + mResumed = true; + } + + @Override + public void onPause() { + mResumed = false; + + if (mCountdownTimer != null) { + mCountdownTimer.cancel(); + mCountdownTimer = null; + } + if (mPendingLockCheck != null) { + mPendingLockCheck.cancel(false); + mPendingLockCheck = null; + } + reset(); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java index ad6ca8582bf08..9ffa658da0e89 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java @@ -178,18 +178,18 @@ public class KeyguardHostViewController extends ViewController /** Initialize the Controller. */ public void init() { super.init(); - mView.setViewMediatorCallback(mViewMediatorCallback); - // Update ViewMediator with the current input method requirements - mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput()); mKeyguardSecurityContainerController.init(); - mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback); - mKeyguardSecurityContainerController.showPrimarySecurityScreen(false); } @Override protected void onViewAttached() { + mView.setViewMediatorCallback(mViewMediatorCallback); + // Update ViewMediator with the current input method requirements + mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput()); mKeyguardUpdateMonitor.registerCallback(mUpdateCallback); mView.setOnKeyListener(mOnKeyListener); + mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback); + mKeyguardSecurityContainerController.showPrimarySecurityScreen(false); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index 552e62052e6f0..c73149c7a8b97 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -17,32 +17,31 @@ package com.android.keyguard; import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.telephony.TelephonyManager; import android.view.MotionEvent; +import android.view.inputmethod.InputMethodManager; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.util.ViewController; +import com.android.systemui.util.concurrency.DelayableExecutor; import javax.inject.Inject; /** Controller for a {@link KeyguardSecurityView}. */ -public class KeyguardInputViewController extends ViewController - implements KeyguardSecurityView { +public abstract class KeyguardInputViewController + extends ViewController implements KeyguardSecurityView { private final SecurityMode mSecurityMode; - private final LockPatternUtils mLockPatternUtils; - private final KeyguardSecurityCallback mKeyguardSecurityCallback; - private KeyguardMessageAreaController mMessageAreaController; protected KeyguardInputViewController(T view, SecurityMode securityMode, - LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback) { super(view); mSecurityMode = securityMode; - mLockPatternUtils = lockPatternUtils; - mKeyguardSecurityCallback = keyguardSecurityCallback; mView.setKeyguardCallback(keyguardSecurityCallback); } @@ -151,16 +150,29 @@ public class KeyguardInputViewController extends Vi private final LockPatternUtils mLockPatternUtils; private final LatencyTracker mLatencyTracker; private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory; + private final InputMethodManager mInputMethodManager; + private final DelayableExecutor mMainExecutor; + private final Resources mResources; + private LiftToActivateListener mLiftToActivateListener; + private TelephonyManager mTelephonyManager; @Inject public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils, LatencyTracker latencyTracker, - KeyguardMessageAreaController.Factory messageAreaControllerFactory) { + KeyguardMessageAreaController.Factory messageAreaControllerFactory, + InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor, + @Main Resources resources, LiftToActivateListener liftToActivateListener, + TelephonyManager telephonyManager) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; mMessageAreaControllerFactory = messageAreaControllerFactory; + mInputMethodManager = inputMethodManager; + mMainExecutor = mainExecutor; + mResources = resources; + mLiftToActivateListener = liftToActivateListener; + mTelephonyManager = telephonyManager; } /** Create a new {@link KeyguardInputViewController}. */ @@ -170,9 +182,29 @@ public class KeyguardInputViewController extends Vi return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mLatencyTracker, mMessageAreaControllerFactory); + } else if (keyguardInputView instanceof KeyguardPasswordView) { + return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView, + mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, + keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, + mInputMethodManager, mMainExecutor, mResources); + } else if (keyguardInputView instanceof KeyguardPINView) { + return new KeyguardPinViewController((KeyguardPINView) keyguardInputView, + mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, + keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, + mLiftToActivateListener); + } else if (keyguardInputView instanceof KeyguardSimPinView) { + return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView, + mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, + keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, + mLiftToActivateListener, mTelephonyManager); + } else if (keyguardInputView instanceof KeyguardSimPukView) { + return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView, + mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, + keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, + mLiftToActivateListener, mTelephonyManager); } - return new KeyguardInputViewController<>(keyguardInputView, securityMode, - mLockPatternUtils, keyguardSecurityCallback); + + throw new RuntimeException("Unable to find controller for " + keyguardInputView); } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java index 12ea1d586e103..bfa187ea099b5 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java @@ -24,7 +24,6 @@ import android.view.animation.AnimationUtils; import com.android.settingslib.animation.AppearAnimationUtils; import com.android.settingslib.animation.DisappearAnimationUtils; -import com.android.systemui.Dependency; import com.android.systemui.R; /** @@ -40,10 +39,8 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { private ViewGroup mRow1; private ViewGroup mRow2; private ViewGroup mRow3; - private View mDivider; private int mDisappearYTranslation; private View[][] mViews; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; public KeyguardPINView(Context context) { this(context, null); @@ -63,15 +60,10 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { mContext, android.R.interpolator.fast_out_linear_in)); mDisappearYTranslation = getResources().getDimensionPixelSize( R.dimen.disappear_y_translation); - mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); } @Override protected void resetState() { - super.resetState(); - if (mSecurityMessageDisplay != null) { - mSecurityMessageDisplay.setMessage(""); - } } @Override @@ -88,7 +80,6 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { mRow1 = findViewById(R.id.row1); mRow2 = findViewById(R.id.row2); mRow3 = findViewById(R.id.row3); - mDivider = findViewById(R.id.divider); mViews = new View[][]{ new View[]{ mRow0, null, null @@ -122,6 +113,16 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { } } + @Override + public void onPause() { + + } + + @Override + public void onResume(int reason) { + + } + @Override public void showUsabilityHint() { } @@ -149,22 +150,24 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { @Override public boolean startDisappearAnimation(final Runnable finishRunnable) { + return false; + } + + public boolean startDisappearAnimation(boolean needsSlowUnlockTransition, + final Runnable finishRunnable) { + enableClipping(false); setTranslationY(0); AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */, mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator()); - DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor - .needsSlowUnlockTransition() + DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition ? mDisappearAnimationUtilsLocked : mDisappearAnimationUtils; disappearAnimationUtils.startAnimation2d(mViews, - new Runnable() { - @Override - public void run() { - enableClipping(true); - if (finishRunnable != null) { - finishRunnable.run(); - } + () -> { + enableClipping(true); + if (finishRunnable != null) { + finishRunnable.run(); } }); return true; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index 97317cf5580f7..3b865922503aa 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -18,48 +18,29 @@ package com.android.keyguard; import android.content.Context; import android.graphics.Rect; -import android.os.UserHandle; -import android.text.Editable; -import android.text.InputType; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.text.method.TextKeyListener; import android.util.AttributeSet; -import android.view.KeyEvent; -import android.view.View; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.TextViewInputDisabler; import com.android.systemui.R; - -import java.util.List; /** * Displays an alphanumeric (latin-1) key entry for the user to enter * an unlock password */ public class KeyguardPasswordView extends KeyguardAbsKeyInputView - implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { + implements KeyguardSecurityView { - private final boolean mShowImeAtScreenOn; private final int mDisappearYTranslation; // A delay constant to be used in a workaround for the situation where InputMethodManagerService // is not switched to the new user yet. // TODO: Remove this by ensuring such a race condition never happens. - private static final int DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON = 500; // 500ms - InputMethodManager mImm; private TextView mPasswordEntry; private TextViewInputDisabler mPasswordEntryDisabler; - private View mSwitchImeButton; private Interpolator mLinearOutSlowInInterpolator; private Interpolator mFastOutLinearInInterpolator; @@ -70,8 +51,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView public KeyguardPasswordView(Context context, AttributeSet attrs) { super(context, attrs); - mShowImeAtScreenOn = context.getResources(). - getBoolean(R.bool.kg_show_ime_at_screen_on); mDisappearYTranslation = getResources().getDimensionPixelSize( R.dimen.disappear_y_translation); mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator( @@ -82,20 +61,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView @Override protected void resetState() { - mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser())); - if (mSecurityMessageDisplay != null) { - mSecurityMessageDisplay.setMessage(""); - } - final boolean wasDisabled = mPasswordEntry.isEnabled(); - setPasswordEntryEnabled(true); - setPasswordEntryInputEnabled(true); - // Don't call showSoftInput when PasswordEntry is invisible or in pausing stage. - if (!mResumed || !mPasswordEntry.isVisibleToUser()) { - return; - } - if (wasDisabled) { - mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT); - } } @Override @@ -103,28 +68,20 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView return R.id.passwordEntry; } + @Override + public void onPause() { + } + + @Override + public void onResume(int reason) { + + } + @Override public boolean needsInput() { return true; } - @Override - public void onResume(final int reason) { - super.onResume(reason); - - // Wait a bit to focus the field so the focusable flag on the window is already set then. - post(new Runnable() { - @Override - public void run() { - if (isShown() && mPasswordEntry.isEnabled()) { - mPasswordEntry.requestFocus(); - if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) { - mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT); - } - } - } - }); - } @Override protected int getPromptReasonStringRes(int reason) { @@ -146,97 +103,13 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView } } - @Override - public void onPause() { - super.onPause(); - mImm.hideSoftInputFromWindow(getWindowToken(), 0); - } - - @Override - public void onStartingToHide() { - mImm.hideSoftInputFromWindow(getWindowToken(), 0); - } - - private void updateSwitchImeButton() { - // If there's more than one IME, enable the IME switcher button - final boolean wasVisible = mSwitchImeButton.getVisibility() == View.VISIBLE; - final boolean shouldBeVisible = hasMultipleEnabledIMEsOrSubtypes(mImm, false); - if (wasVisible != shouldBeVisible) { - mSwitchImeButton.setVisibility(shouldBeVisible ? View.VISIBLE : View.GONE); - } - - // TODO: Check if we still need this hack. - // If no icon is visible, reset the start margin on the password field so the text is - // still centered. - if (mSwitchImeButton.getVisibility() != View.VISIBLE) { - android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams(); - if (params instanceof MarginLayoutParams) { - final MarginLayoutParams mlp = (MarginLayoutParams) params; - mlp.setMarginStart(0); - mPasswordEntry.setLayoutParams(params); - } - } - } @Override protected void onFinishInflate() { super.onFinishInflate(); - mImm = (InputMethodManager) getContext().getSystemService( - Context.INPUT_METHOD_SERVICE); - mPasswordEntry = findViewById(getPasswordTextViewId()); - mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser())); mPasswordEntryDisabler = new TextViewInputDisabler(mPasswordEntry); - mPasswordEntry.setKeyListener(TextKeyListener.getInstance()); - mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT - | InputType.TYPE_TEXT_VARIATION_PASSWORD); - mPasswordEntry.setOnEditorActionListener(this); - mPasswordEntry.addTextChangedListener(this); - - // Poke the wakelock any time the text is selected or modified - mPasswordEntry.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mCallback.userActivity(); - } - }); - - // Set selected property on so the view can send accessibility events. - mPasswordEntry.setSelected(true); - - mSwitchImeButton = findViewById(R.id.switch_ime_button); - mSwitchImeButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mCallback.userActivity(); // Leave the screen on a bit longer - // Do not show auxiliary subtypes in password lock screen. - mImm.showInputMethodPickerFromSystem(false /* showAuxiliarySubtypes */, - getContext().getDisplayId()); - } - }); - - View cancelBtn = findViewById(R.id.cancel_button); - if (cancelBtn != null) { - cancelBtn.setOnClickListener(view -> { - mCallback.reset(); - mCallback.onCancelClicked(); - }); - } - - // If there's more than one IME, enable the IME switcher button - updateSwitchImeButton(); - - // When we the current user is switching, InputMethodManagerService sometimes has not - // switched internal state yet here. As a quick workaround, we check the keyboard state - // again. - // TODO: Remove this workaround by ensuring such a race condition never happens. - postDelayed(new Runnable() { - @Override - public void run() { - updateSwitchImeButton(); - } - }, DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON); } @Override @@ -265,55 +138,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView mPasswordEntryDisabler.setInputEnabled(enabled); } - /** - * Method adapted from com.android.inputmethod.latin.Utils - * - * @param imm The input method manager - * @param shouldIncludeAuxiliarySubtypes - * @return true if we have multiple IMEs to choose from - */ - private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm, - final boolean shouldIncludeAuxiliarySubtypes) { - final List enabledImis = - imm.getEnabledInputMethodListAsUser(KeyguardUpdateMonitor.getCurrentUser()); - - // Number of the filtered IMEs - int filteredImisCount = 0; - - for (InputMethodInfo imi : enabledImis) { - // We can return true immediately after we find two or more filtered IMEs. - if (filteredImisCount > 1) return true; - final List subtypes = - imm.getEnabledInputMethodSubtypeList(imi, true); - // IMEs that have no subtypes should be counted. - if (subtypes.isEmpty()) { - ++filteredImisCount; - continue; - } - - int auxCount = 0; - for (InputMethodSubtype subtype : subtypes) { - if (subtype.isAuxiliary()) { - ++auxCount; - } - } - final int nonAuxCount = subtypes.size() - auxCount; - - // IMEs that have one or more non-auxiliary subtypes should be counted. - // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary - // subtypes should be counted as well. - if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { - ++filteredImisCount; - continue; - } - } - - return filteredImisCount > 1 - // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled - // input method subtype (The current IME should be LatinIME.) - || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; - } - @Override public void showUsabilityHint() { } @@ -345,46 +169,9 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView return true; } - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - if (mCallback != null) { - mCallback.userActivity(); - } - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - @Override - public void afterTextChanged(Editable s) { - // Poor man's user edit detection, assuming empty text is programmatic and everything else - // is from the user. - if (!TextUtils.isEmpty(s)) { - onUserInput(); - } - } - - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - // Check if this was the result of hitting the enter key - final boolean isSoftImeEvent = event == null - && (actionId == EditorInfo.IME_NULL - || actionId == EditorInfo.IME_ACTION_DONE - || actionId == EditorInfo.IME_ACTION_NEXT); - final boolean isKeyboardEnterKey = event != null - && KeyEvent.isConfirmKey(event.getKeyCode()) - && event.getAction() == KeyEvent.ACTION_DOWN; - if (isSoftImeEvent || isKeyboardEnterKey) { - verifyPasswordAndUnlock(); - return true; - } - return false; - } - @Override public CharSequence getTitle() { - return getContext().getString( + return getResources().getString( com.android.internal.R.string.keyguard_accessibility_password_unlock); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java new file mode 100644 index 0000000000000..52afdcd1cacb2 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -0,0 +1,270 @@ +/* + * 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.Resources; +import android.os.UserHandle; +import android.text.Editable; +import android.text.InputType; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.text.method.TextKeyListener; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup.MarginLayoutParams; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + +import com.android.internal.util.LatencyTracker; +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.util.concurrency.DelayableExecutor; + +import java.util.List; + +public class KeyguardPasswordViewController + extends KeyguardAbsKeyInputViewController { + + private static final int DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON = 500; // 500ms + + private final KeyguardSecurityCallback mKeyguardSecurityCallback; + private final InputMethodManager mInputMethodManager; + private final DelayableExecutor mMainExecutor; + private final boolean mShowImeAtScreenOn; + private TextView mPasswordEntry; + private View mSwitchImeButton; + + private final OnEditorActionListener mOnEditorActionListener = (v, actionId, event) -> { + // Check if this was the result of hitting the enter key + final boolean isSoftImeEvent = event == null + && (actionId == EditorInfo.IME_NULL + || actionId == EditorInfo.IME_ACTION_DONE + || actionId == EditorInfo.IME_ACTION_NEXT); + final boolean isKeyboardEnterKey = event != null + && KeyEvent.isConfirmKey(event.getKeyCode()) + && event.getAction() == KeyEvent.ACTION_DOWN; + if (isSoftImeEvent || isKeyboardEnterKey) { + verifyPasswordAndUnlock(); + return true; + } + return false; + }; + + private final TextWatcher mTextWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + mKeyguardSecurityCallback.userActivity(); + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + if (!TextUtils.isEmpty(s)) { + onUserInput(); + } + } + }; + + protected KeyguardPasswordViewController(KeyguardPasswordView view, + KeyguardUpdateMonitor keyguardUpdateMonitor, + SecurityMode securityMode, + LockPatternUtils lockPatternUtils, + KeyguardSecurityCallback keyguardSecurityCallback, + KeyguardMessageAreaController.Factory messageAreaControllerFactory, + LatencyTracker latencyTracker, + InputMethodManager inputMethodManager, + @Main DelayableExecutor mainExecutor, + @Main Resources resources) { + super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, + messageAreaControllerFactory, latencyTracker); + mKeyguardSecurityCallback = keyguardSecurityCallback; + mInputMethodManager = inputMethodManager; + mMainExecutor = mainExecutor; + mShowImeAtScreenOn = resources.getBoolean(R.bool.kg_show_ime_at_screen_on); + mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId()); + mSwitchImeButton = mView.findViewById(R.id.switch_ime_button); + } + + @Override + protected void onViewAttached() { + super.onViewAttached(); + mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser())); + mPasswordEntry.setKeyListener(TextKeyListener.getInstance()); + mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_VARIATION_PASSWORD); + + // Set selected property on so the view can send accessibility events. + mPasswordEntry.setSelected(true); + mPasswordEntry.setOnEditorActionListener(mOnEditorActionListener); + mPasswordEntry.addTextChangedListener(mTextWatcher); + // Poke the wakelock any time the text is selected or modified + mPasswordEntry.setOnClickListener(v -> mKeyguardSecurityCallback.userActivity()); + + mSwitchImeButton.setOnClickListener(v -> { + mKeyguardSecurityCallback.userActivity(); // Leave the screen on a bit longer + // Do not show auxiliary subtypes in password lock screen. + mInputMethodManager.showInputMethodPickerFromSystem(false, + mView.getContext().getDisplayId()); + }); + + View cancelBtn = mView.findViewById(R.id.cancel_button); + if (cancelBtn != null) { + cancelBtn.setOnClickListener(view -> { + mKeyguardSecurityCallback.reset(); + mKeyguardSecurityCallback.onCancelClicked(); + }); + } + + // If there's more than one IME, enable the IME switcher button + updateSwitchImeButton(); + + // When we the current user is switching, InputMethodManagerService sometimes has not + // switched internal state yet here. As a quick workaround, we check the keyboard state + // again. + // TODO: Remove this workaround by ensuring such a race condition never happens. + mMainExecutor.executeDelayed( + this::updateSwitchImeButton, DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON); + } + + @Override + protected void onViewDetached() { + super.onViewDetached(); + mPasswordEntry.setOnEditorActionListener(null); + } + + @Override + void resetState() { + mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser())); + mMessageAreaController.setMessage(""); + final boolean wasDisabled = mPasswordEntry.isEnabled(); + mView.setPasswordEntryEnabled(true); + mView.setPasswordEntryInputEnabled(true); + // Don't call showSoftInput when PasswordEntry is invisible or in pausing stage. + if (!mResumed || !mPasswordEntry.isVisibleToUser()) { + return; + } + if (wasDisabled) { + mInputMethodManager.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT); + } + } + + @Override + public void onResume(int reason) { + super.onResume(reason); + // Wait a bit to focus the field so the focusable flag on the window is already set then. + mMainExecutor.execute(() -> { + if (mView.isShown() && mPasswordEntry.isEnabled()) { + mPasswordEntry.requestFocus(); + if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) { + mInputMethodManager.showSoftInput( + mPasswordEntry, InputMethodManager.SHOW_IMPLICIT); + } + } + }); + } + + @Override + public void onPause() { + super.onPause(); + mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0); + } + + @Override + public void onStartingToHide() { + mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0); + } + + private void updateSwitchImeButton() { + // If there's more than one IME, enable the IME switcher button + final boolean wasVisible = mSwitchImeButton.getVisibility() == View.VISIBLE; + final boolean shouldBeVisible = hasMultipleEnabledIMEsOrSubtypes( + mInputMethodManager, false); + if (wasVisible != shouldBeVisible) { + mSwitchImeButton.setVisibility(shouldBeVisible ? View.VISIBLE : View.GONE); + } + + // TODO: Check if we still need this hack. + // If no icon is visible, reset the start margin on the password field so the text is + // still centered. + if (mSwitchImeButton.getVisibility() != View.VISIBLE) { + android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams(); + if (params instanceof MarginLayoutParams) { + final MarginLayoutParams mlp = (MarginLayoutParams) params; + mlp.setMarginStart(0); + mPasswordEntry.setLayoutParams(params); + } + } + } + + /** + * Method adapted from com.android.inputmethod.latin.Utils + * + * @param imm The input method manager + * @param shouldIncludeAuxiliarySubtypes + * @return true if we have multiple IMEs to choose from + */ + private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm, + final boolean shouldIncludeAuxiliarySubtypes) { + final List enabledImis = + imm.getEnabledInputMethodListAsUser(KeyguardUpdateMonitor.getCurrentUser()); + + // Number of the filtered IMEs + int filteredImisCount = 0; + + for (InputMethodInfo imi : enabledImis) { + // We can return true immediately after we find two or more filtered IMEs. + if (filteredImisCount > 1) return true; + final List subtypes = + imm.getEnabledInputMethodSubtypeList(imi, true); + // IMEs that have no subtypes should be counted. + if (subtypes.isEmpty()) { + ++filteredImisCount; + continue; + } + + int auxCount = 0; + for (InputMethodSubtype subtype : subtypes) { + if (subtype.isAuxiliary()) { + ++auxCount; + } + } + final int nonAuxCount = subtypes.size() - auxCount; + + // IMEs that have one or more non-auxiliary subtypes should be counted. + // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary + // subtypes should be counted as well. + if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { + ++filteredImisCount; + continue; + } + } + + return filteredImisCount > 1 + // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's + //enabled input method subtype (The current IME should be LatinIME.) + || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 5e547d3120bfe..13a16360be040 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -180,18 +180,18 @@ public class KeyguardPatternViewController KeyguardSecurityCallback keyguardSecurityCallback, LatencyTracker latencyTracker, KeyguardMessageAreaController.Factory messageAreaControllerFactory) { - super(view, securityMode, lockPatternUtils, keyguardSecurityCallback); + super(view, securityMode, keyguardSecurityCallback); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; mMessageAreaControllerFactory = messageAreaControllerFactory; + KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView); + mMessageAreaController = mMessageAreaControllerFactory.create(kma); + mLockPatternView = mView.findViewById(R.id.lockPatternView); } @Override protected void onViewAttached() { - KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView); - mMessageAreaController = mMessageAreaControllerFactory.create(kma); - mLockPatternView = mView.findViewById(R.id.lockPatternView); mLockPatternView.setOnPatternListener(new UnlockPatternListener()); mLockPatternView.setSaveEnabled(false); mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index c7f27cf8a71a9..e579380fc8d59 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -20,7 +20,6 @@ import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.view.KeyEvent; -import android.view.MotionEvent; import android.view.View; import com.android.internal.widget.LockscreenCredential; @@ -29,22 +28,12 @@ import com.android.systemui.R; /** * A Pin based Keyguard input view */ -public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView - implements View.OnKeyListener, View.OnTouchListener { +public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView { protected PasswordTextView mPasswordEntry; private View mOkButton; private View mDeleteButton; - private View mButton0; - private View mButton1; - private View mButton2; - private View mButton3; - private View mButton4; - private View mButton5; - private View mButton6; - private View mButton7; - private View mButton8; - private View mButton9; + private View[] mButtons = new View[10]; public KeyguardPinBasedInputView(Context context) { this(context, null); @@ -62,7 +51,6 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView @Override protected void resetState() { - setPasswordEntryEnabled(true); } @Override @@ -86,10 +74,10 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (KeyEvent.isConfirmKey(keyCode)) { - performClick(mOkButton); + mOkButton.performClick(); return true; } else if (keyCode == KeyEvent.KEYCODE_DEL) { - performClick(mDeleteButton); + mDeleteButton.performClick(); return true; } if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) { @@ -125,42 +113,9 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView } } - private void performClick(View view) { - view.performClick(); - } - private void performNumberClick(int number) { - switch (number) { - case 0: - performClick(mButton0); - break; - case 1: - performClick(mButton1); - break; - case 2: - performClick(mButton2); - break; - case 3: - performClick(mButton3); - break; - case 4: - performClick(mButton4); - break; - case 5: - performClick(mButton5); - break; - case 6: - performClick(mButton6); - break; - case 7: - performClick(mButton7); - break; - case 8: - performClick(mButton8); - break; - case 9: - performClick(mButton9); - break; + if (number >= 0 && number <= 9) { + mButtons[number].performClick(); } } @@ -177,93 +132,30 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView @Override protected void onFinishInflate() { mPasswordEntry = findViewById(getPasswordTextViewId()); - mPasswordEntry.setOnKeyListener(this); // Set selected property on so the view can send accessibility events. mPasswordEntry.setSelected(true); - mPasswordEntry.setUserActivityListener(new PasswordTextView.UserActivityListener() { - @Override - public void onUserActivity() { - onUserInput(); - } - }); - mOkButton = findViewById(R.id.key_enter); - if (mOkButton != null) { - mOkButton.setOnTouchListener(this); - mOkButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mPasswordEntry.isEnabled()) { - verifyPasswordAndUnlock(); - } - } - }); - mOkButton.setOnHoverListener(new LiftToActivateListener(getContext())); - } mDeleteButton = findViewById(R.id.delete_button); mDeleteButton.setVisibility(View.VISIBLE); - mDeleteButton.setOnTouchListener(this); - mDeleteButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - // check for time-based lockouts - if (mPasswordEntry.isEnabled()) { - mPasswordEntry.deleteLastChar(); - } - } - }); - mDeleteButton.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - // check for time-based lockouts - if (mPasswordEntry.isEnabled()) { - resetPasswordText(true /* animate */, true /* announce */); - } - doHapticKeyClick(); - return true; - } - }); - mButton0 = findViewById(R.id.key0); - mButton1 = findViewById(R.id.key1); - mButton2 = findViewById(R.id.key2); - mButton3 = findViewById(R.id.key3); - mButton4 = findViewById(R.id.key4); - mButton5 = findViewById(R.id.key5); - mButton6 = findViewById(R.id.key6); - mButton7 = findViewById(R.id.key7); - mButton8 = findViewById(R.id.key8); - mButton9 = findViewById(R.id.key9); + mButtons[0] = findViewById(R.id.key0); + mButtons[1] = findViewById(R.id.key1); + mButtons[2] = findViewById(R.id.key2); + mButtons[3] = findViewById(R.id.key3); + mButtons[4] = findViewById(R.id.key4); + mButtons[5] = findViewById(R.id.key5); + mButtons[6] = findViewById(R.id.key6); + mButtons[7] = findViewById(R.id.key7); + mButtons[8] = findViewById(R.id.key8); + mButtons[9] = findViewById(R.id.key9); mPasswordEntry.requestFocus(); super.onFinishInflate(); } - @Override - public void onResume(int reason) { - super.onResume(reason); - mPasswordEntry.requestFocus(); - } - - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - doHapticKeyClick(); - } - return false; - } - - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - if (event.getAction() == KeyEvent.ACTION_DOWN) { - return onKeyDown(keyCode, event); - } - return false; - } - @Override public CharSequence getTitle() { return getContext().getString( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java new file mode 100644 index 0000000000000..4d0ebfffbe04f --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java @@ -0,0 +1,113 @@ +/* + * 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.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnKeyListener; +import android.view.View.OnTouchListener; + +import com.android.internal.util.LatencyTracker; +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; + +public abstract class KeyguardPinBasedInputViewController + extends KeyguardAbsKeyInputViewController { + + private final LiftToActivateListener mLiftToActivateListener; + protected PasswordTextView mPasswordEntry; + + private final OnKeyListener mOnKeyListener = (v, keyCode, event) -> { + if (event.getAction() == KeyEvent.ACTION_DOWN) { + return mView.onKeyDown(keyCode, event); + } + return false; + }; + + private final OnTouchListener mOnTouchListener = (v, event) -> { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + mView.doHapticKeyClick(); + } + return false; + }; + + protected KeyguardPinBasedInputViewController(T view, + KeyguardUpdateMonitor keyguardUpdateMonitor, + SecurityMode securityMode, + LockPatternUtils lockPatternUtils, + KeyguardSecurityCallback keyguardSecurityCallback, + KeyguardMessageAreaController.Factory messageAreaControllerFactory, + LatencyTracker latencyTracker, + LiftToActivateListener liftToActivateListener) { + super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, + messageAreaControllerFactory, latencyTracker); + mLiftToActivateListener = liftToActivateListener; + mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId()); + } + + @Override + protected void onViewAttached() { + super.onViewAttached(); + + mPasswordEntry.setOnKeyListener(mOnKeyListener); + mPasswordEntry.setUserActivityListener(this::onUserInput); + + View deleteButton = mView.findViewById(R.id.delete_button); + deleteButton.setOnTouchListener(mOnTouchListener); + deleteButton.setOnClickListener(v -> { + // check for time-based lockouts + if (mPasswordEntry.isEnabled()) { + mPasswordEntry.deleteLastChar(); + } + }); + deleteButton.setOnLongClickListener(v -> { + // check for time-based lockouts + if (mPasswordEntry.isEnabled()) { + mView.resetPasswordText(true /* animate */, true /* announce */); + } + mView.doHapticKeyClick(); + return true; + }); + + View okButton = mView.findViewById(R.id.key_enter); + if (okButton != null) { + okButton.setOnTouchListener(mOnTouchListener); + okButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mPasswordEntry.isEnabled()) { + verifyPasswordAndUnlock(); + } + } + }); + okButton.setOnHoverListener(mLiftToActivateListener); + } + } + + @Override + public void onResume(int reason) { + super.onResume(reason); + mPasswordEntry.requestFocus(); + } + + @Override + void resetState() { + mView.setPasswordEntryEnabled(true); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java new file mode 100644 index 0000000000000..625ab5214da15 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java @@ -0,0 +1,50 @@ +/* + * 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 com.android.internal.util.LatencyTracker; +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; + +public class KeyguardPinViewController + extends KeyguardPinBasedInputViewController { + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + + protected KeyguardPinViewController(KeyguardPINView view, + KeyguardUpdateMonitor keyguardUpdateMonitor, + SecurityMode securityMode, LockPatternUtils lockPatternUtils, + KeyguardSecurityCallback keyguardSecurityCallback, + KeyguardMessageAreaController.Factory messageAreaControllerFactory, + LatencyTracker latencyTracker, + LiftToActivateListener liftToActivateListener) { + super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, + messageAreaControllerFactory, latencyTracker, liftToActivateListener); + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + } + + @Override + void resetState() { + super.resetState(); + mMessageAreaController.setMessage(""); + } + + @Override + public boolean startDisappearAnimation(Runnable finishRunnable) { + return mView.startDisappearAnimation( + mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 342f3de2ede31..2c7dce6e43021 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -197,6 +197,7 @@ public class KeyguardSecurityContainerController extends ViewController= 0) { - return; - } - - // Sending empty PIN here to query the number of remaining PIN attempts - new CheckSimPin("", mSubId) { - void onSimCheckResponse(final PinResult result) { - Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result " - + result.toString()); - if (result.getAttemptsRemaining() >= 0) { - mRemainingAttempts = result.getAttemptsRemaining(); - setLockedSimMessage(); - } - } - }.start(); - } - - private void handleSubInfoChangeIfNeeded() { - KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class); - int subId = monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED); - if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) { - mSubId = subId; - mShowDefaultMessage = true; - mRemainingAttempts = -1; - } + esimButton.setVisibility(locked ? View.VISIBLE : View.GONE); } @Override @@ -173,35 +54,6 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { return 0; } - private String getPinPasswordErrorMessage(int attemptsRemaining, boolean isDefault) { - String displayMessage; - int msgId; - if (attemptsRemaining == 0) { - displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked); - } else if (attemptsRemaining > 0) { - msgId = isDefault ? R.plurals.kg_password_default_pin_message : - R.plurals.kg_password_wrong_pin_code; - displayMessage = getContext().getResources() - .getQuantityString(msgId, attemptsRemaining, attemptsRemaining); - } else { - msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed; - displayMessage = getContext().getString(msgId); - } - if (KeyguardEsimArea.isEsimLocked(mContext, mSubId)) { - displayMessage = getResources() - .getString(R.string.kg_sim_lock_esim_instructions, displayMessage); - } - if (DEBUG) Log.d(LOG_TAG, "getPinPasswordErrorMessage:" - + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage); - return displayMessage; - } - - @Override - protected boolean shouldLockout(long deadline) { - // SIM PIN doesn't have a timed lockout - return false; - } - @Override protected int getPasswordTextViewId() { return R.id.simPinEntry; @@ -214,173 +66,21 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { if (mEcaView instanceof EmergencyCarrierArea) { ((EmergencyCarrierArea) mEcaView).setCarrierTextVisible(true); } - mSimImageView = findViewById(R.id.keyguard_sim); } @Override - public void showUsabilityHint() { + public void onPause() { } @Override public void onResume(int reason) { - super.onResume(reason); - Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateMonitorCallback); - resetState(); + } @Override - public void onPause() { - // dismiss the dialog. - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.dismiss(); - mSimUnlockProgressDialog = null; - } - Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mUpdateMonitorCallback); - } + public void showUsabilityHint() { - /** - * Since the IPC can block, we want to run the request in a separate thread - * with a callback. - */ - private abstract class CheckSimPin extends Thread { - private final String mPin; - private int mSubId; - - protected CheckSimPin(String pin, int subId) { - mPin = pin; - mSubId = subId; - } - - abstract void onSimCheckResponse(@NonNull PinResult result); - - @Override - public void run() { - if (DEBUG) { - Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")"); - } - TelephonyManager telephonyManager = - ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)) - .createForSubscriptionId(mSubId); - final PinResult result = telephonyManager.supplyPinReportPinResult(mPin); - if (result == null) { - Log.e(TAG, "Error result for supplyPinReportResult."); - post(new Runnable() { - @Override - public void run() { - onSimCheckResponse(PinResult.getDefaultFailedResult()); - } - }); - } else { - if (DEBUG) { - Log.v(TAG, "supplyPinReportResult returned: " + result.toString()); - } - post(new Runnable() { - @Override - public void run() { - onSimCheckResponse(result); - } - }); - } - } - } - - private Dialog getSimUnlockProgressDialog() { - if (mSimUnlockProgressDialog == null) { - mSimUnlockProgressDialog = new ProgressDialog(mContext); - mSimUnlockProgressDialog.setMessage( - mContext.getString(R.string.kg_sim_unlock_progress_dialog_message)); - mSimUnlockProgressDialog.setIndeterminate(true); - mSimUnlockProgressDialog.setCancelable(false); - mSimUnlockProgressDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } - return mSimUnlockProgressDialog; - } - - private Dialog getSimRemainingAttemptsDialog(int remaining) { - String msg = getPinPasswordErrorMessage(remaining, false); - if (mRemainingAttemptsDialog == null) { - Builder builder = new AlertDialog.Builder(mContext); - builder.setMessage(msg); - builder.setCancelable(false); - builder.setNeutralButton(R.string.ok, null); - mRemainingAttemptsDialog = builder.create(); - mRemainingAttemptsDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } else { - mRemainingAttemptsDialog.setMessage(msg); - } - return mRemainingAttemptsDialog; - } - - @Override - protected void verifyPasswordAndUnlock() { - String entry = mPasswordEntry.getText(); - - if (entry.length() < 4) { - // otherwise, display a message to the user, and don't submit. - mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint); - resetPasswordText(true /* animate */, true /* announce */); - mCallback.userActivity(); - return; - } - - getSimUnlockProgressDialog().show(); - - if (mCheckSimPinThread == null) { - mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText(), mSubId) { - @Override - void onSimCheckResponse(final PinResult result) { - post(new Runnable() { - @Override - public void run() { - mRemainingAttempts = result.getAttemptsRemaining(); - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.hide(); - } - resetPasswordText(true /* animate */, - /* announce */ - result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS); - if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) { - Dependency.get(KeyguardUpdateMonitor.class) - .reportSimUnlocked(mSubId); - mRemainingAttempts = -1; - mShowDefaultMessage = true; - if (mCallback != null) { - mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser()); - } - } else { - mShowDefaultMessage = false; - if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) { - if (result.getAttemptsRemaining() <= 2) { - // this is getting critical - show dialog - getSimRemainingAttemptsDialog( - result.getAttemptsRemaining()).show(); - } else { - // show message - mSecurityMessageDisplay.setMessage( - getPinPasswordErrorMessage( - result.getAttemptsRemaining(), false)); - } - } else { - // "PIN operation failed!" - no idea what this was and no way to - // find out. :/ - mSecurityMessageDisplay.setMessage(getContext().getString( - R.string.kg_password_pin_failed)); - } - if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock " - + " CheckSimPin.onSimCheckResponse: " + result - + " attemptsRemaining=" + result.getAttemptsRemaining()); - } - mCallback.userActivity(); - mCheckSimPinThread = null; - } - }); - } - }; - mCheckSimPinThread.start(); - } } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java new file mode 100644 index 0000000000000..3c29058e0afc2 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard; + +import android.annotation.NonNull; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.telephony.PinResult; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.view.View; +import android.view.WindowManager; +import android.widget.ImageView; + +import com.android.internal.util.LatencyTracker; +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; + +public class KeyguardSimPinViewController + extends KeyguardPinBasedInputViewController { + public static final String TAG = "KeyguardSimPinView"; + private static final String LOG_TAG = "KeyguardSimPinView"; + private static final boolean DEBUG = KeyguardConstants.DEBUG_SIM_STATES; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final TelephonyManager mTelephonyManager; + + private ProgressDialog mSimUnlockProgressDialog; + private CheckSimPin mCheckSimPinThread; + private int mRemainingAttempts; + // Below flag is set to true during power-up or when a new SIM card inserted on device. + // When this is true and when SIM card is PIN locked state, on PIN lock screen, message would + // be displayed to inform user about the number of remaining PIN attempts left. + private boolean mShowDefaultMessage; + private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + private AlertDialog mRemainingAttemptsDialog; + private ImageView mSimImageView; + + KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { + @Override + public void onSimStateChanged(int subId, int slotId, int simState) { + if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")"); + if (simState == TelephonyManager.SIM_STATE_READY) { + mRemainingAttempts = -1; + resetState(); + } else { + resetState(); + } + } + }; + + protected KeyguardSimPinViewController(KeyguardSimPinView view, + KeyguardUpdateMonitor keyguardUpdateMonitor, + SecurityMode securityMode, LockPatternUtils lockPatternUtils, + KeyguardSecurityCallback keyguardSecurityCallback, + KeyguardMessageAreaController.Factory messageAreaControllerFactory, + LatencyTracker latencyTracker, + LiftToActivateListener liftToActivateListener, + TelephonyManager telephonyManager) { + super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, + messageAreaControllerFactory, latencyTracker, liftToActivateListener); + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mTelephonyManager = telephonyManager; + mSimImageView = mView.findViewById(R.id.keyguard_sim); + } + + @Override + protected void onViewAttached() { + super.onViewAttached(); + } + + @Override + void resetState() { + super.resetState(); + if (DEBUG) Log.v(TAG, "Resetting state"); + handleSubInfoChangeIfNeeded(); + mMessageAreaController.setMessage(""); + if (mShowDefaultMessage) { + showDefaultMessage(); + } + + mView.setEsimLocked(KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)); + } + + @Override + public boolean startDisappearAnimation(Runnable finishRunnable) { + return mView.startDisappearAnimation(finishRunnable); + } + + @Override + public void onResume(int reason) { + super.onResume(reason); + mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback); + mView.resetState(); + } + + @Override + public void onPause() { + super.onPause(); + mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback); + + // dismiss the dialog. + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.dismiss(); + mSimUnlockProgressDialog = null; + } + } + + @Override + protected void verifyPasswordAndUnlock() { + String entry = mPasswordEntry.getText(); + + if (entry.length() < 4) { + // otherwise, display a message to the user, and don't submit. + mMessageAreaController.setMessage( + com.android.systemui.R.string.kg_invalid_sim_pin_hint); + mView.resetPasswordText(true /* animate */, true /* announce */); + mKeyguardSecurityCallback.userActivity(); + return; + } + + getSimUnlockProgressDialog().show(); + + if (mCheckSimPinThread == null) { + mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText(), mSubId) { + @Override + void onSimCheckResponse(final PinResult result) { + mView.post(() -> { + mRemainingAttempts = result.getAttemptsRemaining(); + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.hide(); + } + mView.resetPasswordText(true /* animate */, + /* announce */ + result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS); + if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) { + mKeyguardUpdateMonitor.reportSimUnlocked(mSubId); + mRemainingAttempts = -1; + mShowDefaultMessage = true; + mKeyguardSecurityCallback.dismiss( + true, KeyguardUpdateMonitor.getCurrentUser()); + } else { + mShowDefaultMessage = false; + if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) { + if (result.getAttemptsRemaining() <= 2) { + // this is getting critical - show dialog + getSimRemainingAttemptsDialog( + result.getAttemptsRemaining()).show(); + } else { + // show message + mMessageAreaController.setMessage( + getPinPasswordErrorMessage( + result.getAttemptsRemaining(), false)); + } + } else { + // "PIN operation failed!" - no idea what this was and no way to + // find out. :/ + mMessageAreaController.setMessage(mView.getResources().getString( + R.string.kg_password_pin_failed)); + } + if (DEBUG) { + Log.d(LOG_TAG, "verifyPasswordAndUnlock " + + " CheckSimPin.onSimCheckResponse: " + result + + " attemptsRemaining=" + result.getAttemptsRemaining()); + } + } + mKeyguardSecurityCallback.userActivity(); + mCheckSimPinThread = null; + }); + } + }; + mCheckSimPinThread.start(); + } + } + + private Dialog getSimUnlockProgressDialog() { + if (mSimUnlockProgressDialog == null) { + mSimUnlockProgressDialog = new ProgressDialog(mView.getContext()); + mSimUnlockProgressDialog.setMessage( + mView.getResources().getString(R.string.kg_sim_unlock_progress_dialog_message)); + mSimUnlockProgressDialog.setIndeterminate(true); + mSimUnlockProgressDialog.setCancelable(false); + mSimUnlockProgressDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + } + return mSimUnlockProgressDialog; + } + + + private Dialog getSimRemainingAttemptsDialog(int remaining) { + String msg = getPinPasswordErrorMessage(remaining, false); + if (mRemainingAttemptsDialog == null) { + Builder builder = new AlertDialog.Builder(mView.getContext()); + builder.setMessage(msg); + builder.setCancelable(false); + builder.setNeutralButton(R.string.ok, null); + mRemainingAttemptsDialog = builder.create(); + mRemainingAttemptsDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + } else { + mRemainingAttemptsDialog.setMessage(msg); + } + return mRemainingAttemptsDialog; + } + + + private String getPinPasswordErrorMessage(int attemptsRemaining, boolean isDefault) { + String displayMessage; + int msgId; + if (attemptsRemaining == 0) { + displayMessage = mView.getResources().getString( + R.string.kg_password_wrong_pin_code_pukked); + } else if (attemptsRemaining > 0) { + msgId = isDefault ? R.plurals.kg_password_default_pin_message : + R.plurals.kg_password_wrong_pin_code; + displayMessage = mView.getResources() + .getQuantityString(msgId, attemptsRemaining, attemptsRemaining); + } else { + msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed; + displayMessage = mView.getResources().getString(msgId); + } + if (KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)) { + displayMessage = mView.getResources() + .getString(R.string.kg_sim_lock_esim_instructions, displayMessage); + } + if (DEBUG) { + Log.d(LOG_TAG, "getPinPasswordErrorMessage: attemptsRemaining=" + + attemptsRemaining + " displayMessage=" + displayMessage); + } + return displayMessage; + } + + private void showDefaultMessage() { + setLockedSimMessage(); + if (mRemainingAttempts >= 0) { + return; + } + + // Sending empty PIN here to query the number of remaining PIN attempts + new CheckSimPin("", mSubId) { + void onSimCheckResponse(final PinResult result) { + Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result " + + result.toString()); + if (result.getAttemptsRemaining() >= 0) { + mRemainingAttempts = result.getAttemptsRemaining(); + setLockedSimMessage(); + } + } + }.start(); + } + + /** + * Since the IPC can block, we want to run the request in a separate thread + * with a callback. + */ + private abstract class CheckSimPin extends Thread { + private final String mPin; + private int mSubId; + + protected CheckSimPin(String pin, int subId) { + mPin = pin; + mSubId = subId; + } + + abstract void onSimCheckResponse(@NonNull PinResult result); + + @Override + public void run() { + if (DEBUG) { + Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")"); + } + TelephonyManager telephonyManager = + mTelephonyManager.createForSubscriptionId(mSubId); + final PinResult result = telephonyManager.supplyPinReportPinResult(mPin); + if (result == null) { + Log.e(TAG, "Error result for supplyPinReportResult."); + mView.post(() -> onSimCheckResponse(PinResult.getDefaultFailedResult())); + } else { + if (DEBUG) { + Log.v(TAG, "supplyPinReportResult returned: " + result.toString()); + } + mView.post(() -> onSimCheckResponse(result)); + } + } + } + + private void setLockedSimMessage() { + boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId); + int count = 1; + if (mTelephonyManager != null) { + count = mTelephonyManager.getActiveModemCount(); + } + Resources rez = mView.getResources(); + String msg; + TypedArray array = mView.getContext().obtainStyledAttributes( + new int[] { R.attr.wallpaperTextColor }); + int color = array.getColor(0, Color.WHITE); + array.recycle(); + if (count < 2) { + msg = rez.getString(R.string.kg_sim_pin_instructions); + } else { + SubscriptionInfo info = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(mSubId); + CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash + msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName); + if (info != null) { + color = info.getIconTint(); + } + } + if (isEsimLocked) { + msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg); + } + + if (mView.getVisibility() == View.VISIBLE) { + mMessageAreaController.setMessage(msg); + } + mSimImageView.setImageTintList(ColorStateList.valueOf(color)); + } + + private void handleSubInfoChangeIfNeeded() { + int subId = mKeyguardUpdateMonitor + .getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED); + if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) { + mSubId = subId; + mShowDefaultMessage = true; + mRemainingAttempts = -1; + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java index 5148dd709026f..932d9b966fa39 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java @@ -16,27 +16,11 @@ package com.android.keyguard; -import android.annotation.NonNull; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.telephony.PinResult; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; import android.util.AttributeSet; import android.util.Log; -import android.view.View; -import android.view.WindowManager; -import android.widget.ImageView; -import com.android.systemui.Dependency; import com.android.systemui.R; @@ -44,47 +28,10 @@ import com.android.systemui.R; * Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier. */ public class KeyguardSimPukView extends KeyguardPinBasedInputView { - private static final String LOG_TAG = "KeyguardSimPukView"; private static final boolean DEBUG = KeyguardConstants.DEBUG; public static final String TAG = "KeyguardSimPukView"; private ProgressDialog mSimUnlockProgressDialog = null; - private CheckSimPuk mCheckSimPukThread; - - // Below flag is set to true during power-up or when a new SIM card inserted on device. - // When this is true and when SIM card is PUK locked state, on PIN lock screen, message would - // be displayed to inform user about the number of remaining PUK attempts left. - private boolean mShowDefaultMessage = true; - private int mRemainingAttempts = -1; - private String mPukText; - private String mPinText; - private StateMachine mStateMachine = new StateMachine(); - private AlertDialog mRemainingAttemptsDialog; - private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - private ImageView mSimImageView; - - KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { - @Override - public void onSimStateChanged(int subId, int slotId, int simState) { - if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")"); - switch(simState) { - // If the SIM is unlocked via a key sequence through the emergency dialer, it will - // move into the READY state and the PUK lock keyguard should be removed. - case TelephonyManager.SIM_STATE_READY: { - mRemainingAttempts = -1; - mShowDefaultMessage = true; - // mCallback can be null if onSimStateChanged callback is called when keyguard - // isn't active. - if (mCallback != null) { - mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser()); - } - break; - } - default: - resetState(); - } - } - }; public KeyguardSimPukView(Context context) { this(context, null); @@ -94,136 +41,14 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { super(context, attrs); } - private class StateMachine { - final int ENTER_PUK = 0; - final int ENTER_PIN = 1; - final int CONFIRM_PIN = 2; - final int DONE = 3; - private int state = ENTER_PUK; - - public void next() { - int msg = 0; - if (state == ENTER_PUK) { - if (checkPuk()) { - state = ENTER_PIN; - msg = R.string.kg_puk_enter_pin_hint; - } else { - msg = R.string.kg_invalid_sim_puk_hint; - } - } else if (state == ENTER_PIN) { - if (checkPin()) { - state = CONFIRM_PIN; - msg = R.string.kg_enter_confirm_pin_hint; - } else { - msg = R.string.kg_invalid_sim_pin_hint; - } - } else if (state == CONFIRM_PIN) { - if (confirmPin()) { - state = DONE; - msg = R.string.keyguard_sim_unlock_progress_dialog_message; - updateSim(); - } else { - state = ENTER_PIN; // try again? - msg = R.string.kg_invalid_confirm_pin_hint; - } - } - resetPasswordText(true /* animate */, true /* announce */); - if (msg != 0) { - mSecurityMessageDisplay.setMessage(msg); - } - } - - - void reset() { - mPinText=""; - mPukText=""; - state = ENTER_PUK; - handleSubInfoChangeIfNeeded(); - if (mShowDefaultMessage) { - showDefaultMessage(); - } - boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId); - - KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area); - esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE); - mPasswordEntry.requestFocus(); - } - - - } - - private void showDefaultMessage() { - if (mRemainingAttempts >= 0) { - mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage( - mRemainingAttempts, true)); - return; - } - - boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId); - int count = 1; - TelephonyManager telephonyManager = - (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); - if (telephonyManager != null) { - count = telephonyManager.getActiveModemCount(); - } - Resources rez = getResources(); - String msg; - TypedArray array = mContext.obtainStyledAttributes(new int[] { R.attr.wallpaperTextColor }); - int color = array.getColor(0, Color.WHITE); - array.recycle(); - if (count < 2) { - msg = rez.getString(R.string.kg_puk_enter_puk_hint); - } else { - SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class) - .getSubscriptionInfoForSubId(mSubId); - CharSequence displayName = info != null ? info.getDisplayName() : ""; - msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName); - if (info != null) { - color = info.getIconTint(); - } - } - if (isEsimLocked) { - msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg); - } - if (mSecurityMessageDisplay != null) { - mSecurityMessageDisplay.setMessage(msg); - } - mSimImageView.setImageTintList(ColorStateList.valueOf(color)); - - // Sending empty PUK here to query the number of remaining PIN attempts - new CheckSimPuk("", "", mSubId) { - void onSimLockChangedResponse(final PinResult result) { - if (result == null) Log.e(LOG_TAG, "onSimCheckResponse, pin result is NULL"); - else { - Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result " - + result.toString()); - if (result.getAttemptsRemaining() >= 0) { - mRemainingAttempts = result.getAttemptsRemaining(); - mSecurityMessageDisplay.setMessage( - getPukPasswordErrorMessage(result.getAttemptsRemaining(), true)); - } - } - } - }.start(); - } - - private void handleSubInfoChangeIfNeeded() { - KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class); - int subId = monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PUK_REQUIRED); - if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) { - mSubId = subId; - mShowDefaultMessage = true; - mRemainingAttempts = -1; - } - } - @Override protected int getPromptReasonStringRes(int reason) { // No message on SIM Puk return 0; } - private String getPukPasswordErrorMessage(int attemptsRemaining, boolean isDefault) { + String getPukPasswordErrorMessage( + int attemptsRemaining, boolean isDefault, boolean isEsimLocked) { String displayMessage; if (attemptsRemaining == 0) { @@ -238,27 +63,18 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { R.string.kg_password_puk_failed; displayMessage = getContext().getString(msgId); } - if (KeyguardEsimArea.isEsimLocked(mContext, mSubId)) { + if (isEsimLocked) { displayMessage = getResources() .getString(R.string.kg_sim_lock_esim_instructions, displayMessage); } - if (DEBUG) Log.d(LOG_TAG, "getPukPasswordErrorMessage:" - + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage); + if (DEBUG) { + Log.d(TAG, "getPukPasswordErrorMessage:" + + " attemptsRemaining=" + attemptsRemaining + + " displayMessage=" + displayMessage); + } return displayMessage; } - @Override - public void resetState() { - super.resetState(); - mStateMachine.reset(); - } - - @Override - protected boolean shouldLockout(long deadline) { - // SIM PUK doesn't have a timed lockout - return false; - } - @Override protected int getPasswordTextViewId() { return R.id.pukEntry; @@ -271,20 +87,6 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { if (mEcaView instanceof EmergencyCarrierArea) { ((EmergencyCarrierArea) mEcaView).setCarrierTextVisible(true); } - mSimImageView = findViewById(R.id.keyguard_sim); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateMonitorCallback); - resetState(); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mUpdateMonitorCallback); } @Override @@ -300,168 +102,8 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { } } - /** - * Since the IPC can block, we want to run the request in a separate thread - * with a callback. - */ - private abstract class CheckSimPuk extends Thread { - - private final String mPin, mPuk; - private final int mSubId; - - protected CheckSimPuk(String puk, String pin, int subId) { - mPuk = puk; - mPin = pin; - mSubId = subId; - } - - abstract void onSimLockChangedResponse(@NonNull PinResult result); - - @Override - public void run() { - if (DEBUG) Log.v(TAG, "call supplyPukReportResult()"); - TelephonyManager telephonyManager = - ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)) - .createForSubscriptionId(mSubId); - final PinResult result = telephonyManager.supplyPukReportPinResult(mPuk, mPin); - if (result == null) { - Log.e(TAG, "Error result for supplyPukReportResult."); - post(new Runnable() { - @Override - public void run() { - onSimLockChangedResponse(PinResult.getDefaultFailedResult()); - } - }); - } else { - if (DEBUG) { - Log.v(TAG, "supplyPukReportResult returned: " + result.toString()); - } - post(new Runnable() { - @Override - public void run() { - onSimLockChangedResponse(result); - } - }); - } - } - } - - private Dialog getSimUnlockProgressDialog() { - if (mSimUnlockProgressDialog == null) { - mSimUnlockProgressDialog = new ProgressDialog(mContext); - mSimUnlockProgressDialog.setMessage( - mContext.getString(R.string.kg_sim_unlock_progress_dialog_message)); - mSimUnlockProgressDialog.setIndeterminate(true); - mSimUnlockProgressDialog.setCancelable(false); - if (!(mContext instanceof Activity)) { - mSimUnlockProgressDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } - } - return mSimUnlockProgressDialog; - } - - private Dialog getPukRemainingAttemptsDialog(int remaining) { - String msg = getPukPasswordErrorMessage(remaining, false); - if (mRemainingAttemptsDialog == null) { - AlertDialog.Builder builder = new AlertDialog.Builder(mContext); - builder.setMessage(msg); - builder.setCancelable(false); - builder.setNeutralButton(R.string.ok, null); - mRemainingAttemptsDialog = builder.create(); - mRemainingAttemptsDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } else { - mRemainingAttemptsDialog.setMessage(msg); - } - return mRemainingAttemptsDialog; - } - - private boolean checkPuk() { - // make sure the puk is at least 8 digits long. - if (mPasswordEntry.getText().length() == 8) { - mPukText = mPasswordEntry.getText(); - return true; - } - return false; - } - - private boolean checkPin() { - // make sure the PIN is between 4 and 8 digits - int length = mPasswordEntry.getText().length(); - if (length >= 4 && length <= 8) { - mPinText = mPasswordEntry.getText(); - return true; - } - return false; - } - - public boolean confirmPin() { - return mPinText.equals(mPasswordEntry.getText()); - } - - private void updateSim() { - getSimUnlockProgressDialog().show(); - - if (mCheckSimPukThread == null) { - mCheckSimPukThread = new CheckSimPuk(mPukText, mPinText, mSubId) { - @Override - void onSimLockChangedResponse(final PinResult result) { - post(new Runnable() { - @Override - public void run() { - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.hide(); - } - resetPasswordText(true /* animate */, - /* announce */ - result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS); - if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) { - Dependency.get(KeyguardUpdateMonitor.class) - .reportSimUnlocked(mSubId); - mRemainingAttempts = -1; - mShowDefaultMessage = true; - if (mCallback != null) { - mCallback.dismiss(true, - KeyguardUpdateMonitor.getCurrentUser()); - } - } else { - mShowDefaultMessage = false; - if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) { - // show message - mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage( - result.getAttemptsRemaining(), false)); - if (result.getAttemptsRemaining() <= 2) { - // this is getting critical - show dialog - getPukRemainingAttemptsDialog( - result.getAttemptsRemaining()).show(); - } else { - // show message - mSecurityMessageDisplay.setMessage( - getPukPasswordErrorMessage( - result.getAttemptsRemaining(), false)); - } - } else { - mSecurityMessageDisplay.setMessage(getContext().getString( - R.string.kg_password_puk_failed)); - } - if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock " - + " UpdateSim.onSimCheckResponse: " - + " attemptsRemaining=" + result.getAttemptsRemaining()); - } - mStateMachine.reset(); - mCheckSimPukThread = null; - } - }); - } - }; - mCheckSimPukThread.start(); - } - } - @Override - protected void verifyPasswordAndUnlock() { - mStateMachine.next(); + public void onResume(int reason) { } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java new file mode 100644 index 0000000000000..9b2166b044155 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard; + +import android.annotation.NonNull; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.telephony.PinResult; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.view.View; +import android.view.WindowManager; +import android.widget.ImageView; + +import com.android.internal.util.LatencyTracker; +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.Dependency; +import com.android.systemui.R; + +public class KeyguardSimPukViewController + extends KeyguardPinBasedInputViewController { + private static final boolean DEBUG = KeyguardConstants.DEBUG; + public static final String TAG = "KeyguardSimPukView"; + + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final TelephonyManager mTelephonyManager; + + private String mPukText; + private String mPinText; + private int mRemainingAttempts; + // Below flag is set to true during power-up or when a new SIM card inserted on device. + // When this is true and when SIM card is PUK locked state, on PIN lock screen, message would + // be displayed to inform user about the number of remaining PUK attempts left. + private boolean mShowDefaultMessage; + private StateMachine mStateMachine = new StateMachine(); + private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + private CheckSimPuk mCheckSimPukThread; + private ProgressDialog mSimUnlockProgressDialog; + + KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { + @Override + public void onSimStateChanged(int subId, int slotId, int simState) { + if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")"); + // If the SIM is unlocked via a key sequence through the emergency dialer, it will + // move into the READY state and the PUK lock keyguard should be removed. + if (simState == TelephonyManager.SIM_STATE_READY) { + mRemainingAttempts = -1; + mShowDefaultMessage = true; + mKeyguardSecurityCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser()); + } else { + resetState(); + } + } + }; + private ImageView mSimImageView; + private AlertDialog mRemainingAttemptsDialog; + + protected KeyguardSimPukViewController(KeyguardSimPukView view, + KeyguardUpdateMonitor keyguardUpdateMonitor, + SecurityMode securityMode, LockPatternUtils lockPatternUtils, + KeyguardSecurityCallback keyguardSecurityCallback, + KeyguardMessageAreaController.Factory messageAreaControllerFactory, + LatencyTracker latencyTracker, + LiftToActivateListener liftToActivateListener, + TelephonyManager telephonyManager) { + super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, + messageAreaControllerFactory, latencyTracker, liftToActivateListener); + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mTelephonyManager = telephonyManager; + mSimImageView = mView.findViewById(R.id.keyguard_sim); + } + + @Override + protected void onViewAttached() { + super.onViewAttached(); + mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback); + } + + @Override + protected void onViewDetached() { + super.onViewDetached(); + mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback); + } + + @Override + void resetState() { + super.resetState(); + mStateMachine.reset(); + } + + @Override + protected void verifyPasswordAndUnlock() { + mStateMachine.next(); + } + + private class StateMachine { + static final int ENTER_PUK = 0; + static final int ENTER_PIN = 1; + static final int CONFIRM_PIN = 2; + static final int DONE = 3; + + private int mState = ENTER_PUK; + + public void next() { + int msg = 0; + if (mState == ENTER_PUK) { + if (checkPuk()) { + mState = ENTER_PIN; + msg = com.android.systemui.R.string.kg_puk_enter_pin_hint; + } else { + msg = com.android.systemui.R.string.kg_invalid_sim_puk_hint; + } + } else if (mState == ENTER_PIN) { + if (checkPin()) { + mState = CONFIRM_PIN; + msg = com.android.systemui.R.string.kg_enter_confirm_pin_hint; + } else { + msg = com.android.systemui.R.string.kg_invalid_sim_pin_hint; + } + } else if (mState == CONFIRM_PIN) { + if (confirmPin()) { + mState = DONE; + msg = com.android.systemui.R.string.keyguard_sim_unlock_progress_dialog_message; + updateSim(); + } else { + mState = ENTER_PIN; // try again? + msg = com.android.systemui.R.string.kg_invalid_confirm_pin_hint; + } + } + mView.resetPasswordText(true /* animate */, true /* announce */); + if (msg != 0) { + mMessageAreaController.setMessage(msg); + } + } + + + void reset() { + mPinText = ""; + mPukText = ""; + mState = ENTER_PUK; + handleSubInfoChangeIfNeeded(); + if (mShowDefaultMessage) { + showDefaultMessage(); + } + boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId); + + KeyguardEsimArea esimButton = mView.findViewById(R.id.keyguard_esim_area); + esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE); + mPasswordEntry.requestFocus(); + } + } + + private void showDefaultMessage() { + if (mRemainingAttempts >= 0) { + mMessageAreaController.setMessage(mView.getPukPasswordErrorMessage( + mRemainingAttempts, true, + KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId))); + return; + } + + boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId); + int count = 1; + if (mTelephonyManager != null) { + count = mTelephonyManager.getActiveModemCount(); + } + Resources rez = mView.getResources(); + String msg; + TypedArray array = mView.getContext().obtainStyledAttributes( + new int[] { R.attr.wallpaperTextColor }); + int color = array.getColor(0, Color.WHITE); + array.recycle(); + if (count < 2) { + msg = rez.getString(R.string.kg_puk_enter_puk_hint); + } else { + SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class) + .getSubscriptionInfoForSubId(mSubId); + CharSequence displayName = info != null ? info.getDisplayName() : ""; + msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName); + if (info != null) { + color = info.getIconTint(); + } + } + if (isEsimLocked) { + msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg); + } + mMessageAreaController.setMessage(msg); + mSimImageView.setImageTintList(ColorStateList.valueOf(color)); + + // Sending empty PUK here to query the number of remaining PIN attempts + new CheckSimPuk("", "", mSubId) { + void onSimLockChangedResponse(final PinResult result) { + if (result == null) Log.e(TAG, "onSimCheckResponse, pin result is NULL"); + else { + Log.d(TAG, "onSimCheckResponse " + " empty One result " + + result.toString()); + if (result.getAttemptsRemaining() >= 0) { + mRemainingAttempts = result.getAttemptsRemaining(); + mMessageAreaController.setMessage( + mView.getPukPasswordErrorMessage( + result.getAttemptsRemaining(), true, + KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId))); + } + } + } + }.start(); + } + + private boolean checkPuk() { + // make sure the puk is at least 8 digits long. + if (mPasswordEntry.getText().length() == 8) { + mPukText = mPasswordEntry.getText(); + return true; + } + return false; + } + + private boolean checkPin() { + // make sure the PIN is between 4 and 8 digits + int length = mPasswordEntry.getText().length(); + if (length >= 4 && length <= 8) { + mPinText = mPasswordEntry.getText(); + return true; + } + return false; + } + + public boolean confirmPin() { + return mPinText.equals(mPasswordEntry.getText()); + } + + + + + private void updateSim() { + getSimUnlockProgressDialog().show(); + + if (mCheckSimPukThread == null) { + mCheckSimPukThread = new CheckSimPuk(mPukText, mPinText, mSubId) { + @Override + void onSimLockChangedResponse(final PinResult result) { + mView.post(() -> { + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.hide(); + } + mView.resetPasswordText(true /* animate */, + /* announce */ + result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS); + if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) { + mKeyguardUpdateMonitor.reportSimUnlocked(mSubId); + mRemainingAttempts = -1; + mShowDefaultMessage = true; + + mKeyguardSecurityCallback.dismiss( + true, KeyguardUpdateMonitor.getCurrentUser()); + } else { + mShowDefaultMessage = false; + if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) { + // show message + mMessageAreaController.setMessage(mView.getPukPasswordErrorMessage( + result.getAttemptsRemaining(), false, + KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId))); + if (result.getAttemptsRemaining() <= 2) { + // this is getting critical - show dialog + getPukRemainingAttemptsDialog( + result.getAttemptsRemaining()).show(); + } else { + // show message + mMessageAreaController.setMessage( + mView.getPukPasswordErrorMessage( + result.getAttemptsRemaining(), false, + KeyguardEsimArea.isEsimLocked( + mView.getContext(), mSubId))); + } + } else { + mMessageAreaController.setMessage(mView.getResources().getString( + R.string.kg_password_puk_failed)); + } + if (DEBUG) { + Log.d(TAG, "verifyPasswordAndUnlock " + + " UpdateSim.onSimCheckResponse: " + + " attemptsRemaining=" + result.getAttemptsRemaining()); + } + } + mStateMachine.reset(); + mCheckSimPukThread = null; + }); + } + }; + mCheckSimPukThread.start(); + } + } + + @Override + protected boolean shouldLockout(long deadline) { + // SIM PUK doesn't have a timed lockout + return false; + } + + private Dialog getSimUnlockProgressDialog() { + if (mSimUnlockProgressDialog == null) { + mSimUnlockProgressDialog = new ProgressDialog(mView.getContext()); + mSimUnlockProgressDialog.setMessage( + mView.getResources().getString(R.string.kg_sim_unlock_progress_dialog_message)); + mSimUnlockProgressDialog.setIndeterminate(true); + mSimUnlockProgressDialog.setCancelable(false); + if (!(mView.getContext() instanceof Activity)) { + mSimUnlockProgressDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + } + } + return mSimUnlockProgressDialog; + } + + private void handleSubInfoChangeIfNeeded() { + int subId = mKeyguardUpdateMonitor.getNextSubIdForState( + TelephonyManager.SIM_STATE_PUK_REQUIRED); + if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) { + mSubId = subId; + mShowDefaultMessage = true; + mRemainingAttempts = -1; + } + } + + + private Dialog getPukRemainingAttemptsDialog(int remaining) { + String msg = mView.getPukPasswordErrorMessage(remaining, false, + KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)); + if (mRemainingAttemptsDialog == null) { + AlertDialog.Builder builder = new AlertDialog.Builder(mView.getContext()); + builder.setMessage(msg); + builder.setCancelable(false); + builder.setNeutralButton(R.string.ok, null); + mRemainingAttemptsDialog = builder.create(); + mRemainingAttemptsDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + } else { + mRemainingAttemptsDialog.setMessage(msg); + } + return mRemainingAttemptsDialog; + } + + /** + * Since the IPC can block, we want to run the request in a separate thread + * with a callback. + */ + private abstract class CheckSimPuk extends Thread { + + private final String mPin, mPuk; + private final int mSubId; + + protected CheckSimPuk(String puk, String pin, int subId) { + mPuk = puk; + mPin = pin; + mSubId = subId; + } + + abstract void onSimLockChangedResponse(@NonNull PinResult result); + + @Override + public void run() { + if (DEBUG) Log.v(TAG, "call supplyPukReportResult()"); + TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); + final PinResult result = telephonyManager.supplyPukReportPinResult(mPuk, mPin); + if (result == null) { + Log.e(TAG, "Error result for supplyPukReportResult."); + mView.post(() -> onSimLockChangedResponse(PinResult.getDefaultFailedResult())); + } else { + if (DEBUG) { + Log.v(TAG, "supplyPukReportResult returned: " + result.toString()); + } + mView.post(new Runnable() { + @Override + public void run() { + onSimLockChangedResponse(result); + } + }); + } + } + } + +} diff --git a/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java b/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java index e59602b1cfffc..425e50ed63975 100644 --- a/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java +++ b/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java @@ -16,11 +16,12 @@ package com.android.keyguard; -import android.content.Context; import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityManager; +import javax.inject.Inject; + /** * Hover listener that implements lift-to-activate interaction for * accessibility. May be added to multiple views. @@ -31,9 +32,9 @@ class LiftToActivateListener implements View.OnHoverListener { private boolean mCachedClickableState; - public LiftToActivateListener(Context context) { - mAccessibilityManager = (AccessibilityManager) context.getSystemService( - Context.ACCESSIBILITY_SERVICE); + @Inject + LiftToActivateListener(AccessibilityManager accessibilityManager) { + mAccessibilityManager = accessibilityManager; } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java index b0457fce6a1a0..2205fdd4267d5 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java @@ -26,6 +26,7 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityManager; import android.widget.TextView; import com.android.internal.widget.LockPatternUtils; @@ -90,7 +91,8 @@ public class NumPadKey extends ViewGroup { } setOnClickListener(mListener); - setOnHoverListener(new LiftToActivateListener(context)); + setOnHoverListener(new LiftToActivateListener( + (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE))); mLockPatternUtils = new LockPatternUtils(context); mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java index b35579d3624ba..79925bad3cc78 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java @@ -62,6 +62,7 @@ import android.view.ViewConfiguration; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; +import android.view.inputmethod.InputMethodManager; import com.android.internal.app.IBatteryStats; import com.android.internal.statusbar.IStatusBarService; @@ -181,6 +182,12 @@ public class FrameworkServicesModule { return context.getSystemService(FingerprintManager.class); } + @Provides + @Singleton + static InputMethodManager provideInputMethodManager(Context context) { + return context.getSystemService(InputMethodManager.class); + } + @Provides @Singleton static IPackageManager provideIPackageManager() { diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java index 64f8dbbb9e34d..f30472f75d298 100644 --- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java +++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java @@ -23,7 +23,20 @@ import android.view.View.OnAttachStateChangeListener; * Utility class that handles view lifecycle events for View Controllers. * * Implementations should handle setup and teardown related activities inside of - * {@link #onViewAttached()} and {@link #onViewDetached()}. + * {@link #onViewAttached()} and {@link #onViewDetached()}. Be sure to call {@link #init()} on + * any child controllers that this uses. This can be done in {@link init()} if the controllers + * are injected, or right after creation time of the child controller. + * + * Tip: View "attachment" happens top down - parents are notified that they are attached before + * any children. That means that if you call a method on a child controller in + * {@link #onViewAttached()}, the child controller may not have had its onViewAttach method + * called, so it may not be fully set up. + * + * As such, make sure that methods on your controller are safe to call _before_ its {@link #init()} + * and {@link #onViewAttached()} methods are called. Specifically, if your controller must call + * {@link View#findViewById(int)} on its root view to setup member variables, do so in its + * constructor. Save {@link #onViewAttached()} for things that can happen post-construction - adding + * listeners, dynamically changing content, or other runtime decisions. * * @param View class that this ViewController is for. */ diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java new file mode 100644 index 0000000000000..2d6ecb6f877e4 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -0,0 +1,120 @@ +/* + * 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.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.view.KeyEvent; + +import androidx.test.filters.SmallTest; + +import com.android.internal.util.LatencyTracker; +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { + + @Mock + private KeyguardAbsKeyInputView mAbsKeyInputView; + @Mock + private PasswordTextView mPasswordEntry; + @Mock + private KeyguardMessageArea mKeyguardMessageArea; + @Mock + private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock + private SecurityMode mSecurityMode; + @Mock + private LockPatternUtils mLockPatternUtils; + @Mock + private KeyguardSecurityCallback mKeyguardSecurityCallback; + @Mock + private KeyguardMessageAreaController.Factory mKeyguardMessageAreaControllerFactory; + @Mock + private KeyguardMessageAreaController mKeyguardMessageAreaController; + @Mock + private LatencyTracker mLatencyTracker; + + private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class))) + .thenReturn(mKeyguardMessageAreaController); + when(mAbsKeyInputView.getPasswordTextViewId()).thenReturn(1); + when(mAbsKeyInputView.findViewById(1)).thenReturn(mPasswordEntry); + when(mAbsKeyInputView.isAttachedToWindow()).thenReturn(true); + when(mAbsKeyInputView.findViewById(R.id.keyguard_message_area)) + .thenReturn(mKeyguardMessageArea); + mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView, + mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, + mKeyguardMessageAreaControllerFactory, mLatencyTracker) { + @Override + void resetState() { + } + + @Override + public void onResume(int reason) { + super.onResume(reason); + } + }; + mKeyguardAbsKeyInputViewController.init(); + } + + @Test + public void onKeyDown_clearsSecurityMessage() { + ArgumentCaptor onKeyDownListenerArgumentCaptor = + ArgumentCaptor.forClass(KeyDownListener.class); + verify(mAbsKeyInputView).setKeyDownListener(onKeyDownListenerArgumentCaptor.capture()); + onKeyDownListenerArgumentCaptor.getValue().onKeyDown( + KeyEvent.KEYCODE_0, mock(KeyEvent.class)); + verify(mKeyguardSecurityCallback).userActivity(); + verify(mKeyguardMessageAreaController).setMessage(eq("")); + } + + @Test + public void onKeyDown_noSecurityMessageInteraction() { + ArgumentCaptor onKeyDownListenerArgumentCaptor = + ArgumentCaptor.forClass(KeyDownListener.class); + verify(mAbsKeyInputView).setKeyDownListener(onKeyDownListenerArgumentCaptor.capture()); + onKeyDownListenerArgumentCaptor.getValue().onKeyDown( + KeyEvent.KEYCODE_UNKNOWN, mock(KeyEvent.class)); + verifyZeroInteractions(mKeyguardSecurityCallback); + verifyZeroInteractions(mKeyguardMessageAreaController); + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java new file mode 100644 index 0000000000000..4944284698a05 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -0,0 +1,106 @@ +/* + * 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.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.view.View; + +import androidx.test.filters.SmallTest; + +import com.android.internal.util.LatencyTracker; +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { + + @Mock + private KeyguardPinBasedInputView mPinBasedInputView; + @Mock + private PasswordTextView mPasswordEntry; + @Mock + private KeyguardMessageArea mKeyguardMessageArea; + @Mock + private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock + private SecurityMode mSecurityMode; + @Mock + private LockPatternUtils mLockPatternUtils; + @Mock + private KeyguardSecurityCallback mKeyguardSecurityCallback; + @Mock + private KeyguardMessageAreaController.Factory mKeyguardMessageAreaControllerFactory; + @Mock + private KeyguardMessageAreaController mKeyguardMessageAreaController; + @Mock + private LatencyTracker mLatencyTracker; + @Mock + private LiftToActivateListener mLiftToactivateListener; + @Mock + private View mDeleteButton; + @Mock + private View mOkButton; + + private KeyguardPinBasedInputViewController mKeyguardPinViewController; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class))) + .thenReturn(mKeyguardMessageAreaController); + when(mPinBasedInputView.getPasswordTextViewId()).thenReturn(1); + when(mPinBasedInputView.findViewById(1)).thenReturn(mPasswordEntry); + when(mPinBasedInputView.isAttachedToWindow()).thenReturn(true); + when(mPinBasedInputView.findViewById(R.id.keyguard_message_area)) + .thenReturn(mKeyguardMessageArea); + when(mPinBasedInputView.findViewById(R.id.delete_button)) + .thenReturn(mDeleteButton); + when(mPinBasedInputView.findViewById(R.id.key_enter)) + .thenReturn(mOkButton); + mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView, + mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, + mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener) { + @Override + public void onResume(int reason) { + super.onResume(reason); + } + }; + mKeyguardPinViewController.init(); + } + + @Test + public void onResume_requestsFocus() { + mKeyguardPinViewController.onResume(KeyguardSecurityView.SCREEN_ON); + verify(mPasswordEntry).requestFocus(); + } +} + diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java deleted file mode 100644 index 6666a926c68b7..0000000000000 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2018 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.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper.RunWithLooper; -import android.view.KeyEvent; -import android.view.LayoutInflater; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@RunWithLooper -public class KeyguardPinBasedInputViewTest extends SysuiTestCase { - - @Mock - private PasswordTextView mPasswordEntry; - @Mock - private SecurityMessageDisplay mSecurityMessageDisplay; - @InjectMocks - private KeyguardPinBasedInputView mKeyguardPinView; - - @Before - public void setup() { - LayoutInflater inflater = LayoutInflater.from(getContext()); - mDependency.injectMockDependency(KeyguardUpdateMonitor.class); - mKeyguardPinView = - (KeyguardPinBasedInputView) inflater.inflate(R.layout.keyguard_pin_view, null); - MockitoAnnotations.initMocks(this); - } - - @Test - public void onResume_requestsFocus() { - mKeyguardPinView.onResume(KeyguardSecurityView.SCREEN_ON); - verify(mPasswordEntry).requestFocus(); - } - - @Test - public void onKeyDown_clearsSecurityMessage() { - mKeyguardPinView.onKeyDown(KeyEvent.KEYCODE_0, mock(KeyEvent.class)); - verify(mSecurityMessageDisplay).setMessage(eq("")); - } - - @Test - public void onKeyDown_noSecurityMessageInteraction() { - mKeyguardPinView.onKeyDown(KeyEvent.KEYCODE_UNKNOWN, mock(KeyEvent.class)); - verifyZeroInteractions(mSecurityMessageDisplay); - } -} From 3b7e026c067af221f040ceea6da97cb354dad2a3 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Wed, 23 Sep 2020 14:01:33 +0000 Subject: [PATCH 5/7] Revert^2 "8/N Remove View Injection from KeyguardMessageArea" dd7312c20ad29c133a32ffd170919bec5f98f215 Change-Id: Idca486311380b48e1f0808c8d08cfce46c929473 --- .../KeyguardAbsKeyInputViewController.java | 6 ++ .../keyguard/KeyguardDisplayManager.java | 15 ++-- .../android/keyguard/KeyguardMessageArea.java | 73 ++-------------- .../KeyguardMessageAreaController.java | 36 ++++++++ .../KeyguardPatternViewController.java | 6 ++ ...KeyguardSecurityViewFlipperController.java | 4 +- .../util/InjectionInflationController.java | 6 -- ...KeyguardAbsKeyInputViewControllerTest.java | 2 + .../keyguard/KeyguardClockSwitchTest.java | 9 +- .../KeyguardMessageAreaControllerTest.java | 87 +++++++++++++++++++ .../keyguard/KeyguardMessageAreaTest.java | 55 ++++++------ .../keyguard/KeyguardPresentationTest.java | 9 +- ...uardSecurityViewFlipperControllerTest.java | 7 +- .../keyguard/KeyguardStatusViewTest.java | 10 +-- 14 files changed, 180 insertions(+), 145 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index a33cef3bbd796..261534e06f605 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -81,6 +81,12 @@ public abstract class KeyguardAbsKeyInputViewController { if (newPresentation.equals(mPresentations.get(displayId))) { mPresentations.remove(displayId); @@ -250,7 +245,7 @@ public class KeyguardDisplayManager { private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; - private final LayoutInflater mInjectableLayoutInflater; + private final LayoutInflater mLayoutInflater; private KeyguardClockSwitchController mKeyguardClockSwitchController; private View mClock; private int mUsableWidth; @@ -270,10 +265,10 @@ public class KeyguardDisplayManager { KeyguardPresentation(Context context, Display display, KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, - LayoutInflater injectionLayoutInflater) { + LayoutInflater layoutInflater) { super(context, display, R.style.Theme_SystemUI_KeyguardPresentation); mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; - mInjectableLayoutInflater = injectionLayoutInflater; + mLayoutInflater = layoutInflater; getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); setCancelable(false); } @@ -299,7 +294,7 @@ public class KeyguardDisplayManager { mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200; mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200; - setContentView(mInjectableLayoutInflater.inflate(R.layout.keyguard_presentation, null)); + setContentView(mLayoutInflater.inflate(R.layout.keyguard_presentation, null)); // Logic to make the lock screen fullscreen getWindow().getDecorView().setSystemUiVisibility( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java index a8b1451d92c77..1a0a4370fca42 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java @@ -16,8 +16,6 @@ package com.android.keyguard; -import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; - import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; @@ -31,20 +29,14 @@ import android.util.TypedValue; import android.view.View; import android.widget.TextView; -import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.statusbar.policy.ConfigurationController; import java.lang.ref.WeakReference; -import javax.inject.Inject; -import javax.inject.Named; - /*** * Manages a number of views inside of the given layout. See below for a list of widgets. */ -public class KeyguardMessageArea extends TextView implements SecurityMessageDisplay, - ConfigurationController.ConfigurationListener { +public class KeyguardMessageArea extends TextView implements SecurityMessageDisplay { /** Handler token posted with accessibility announcement runnables. */ private static final Object ANNOUNCE_TOKEN = new Object(); @@ -56,71 +48,26 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp private static final int DEFAULT_COLOR = -1; private final Handler mHandler; - private final ConfigurationController mConfigurationController; private ColorStateList mDefaultColorState; private CharSequence mMessage; private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR); private boolean mBouncerVisible; - private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - public void onFinishedGoingToSleep(int why) { - setSelected(false); - } - - public void onStartedWakingUp() { - setSelected(true); - } - - @Override - public void onKeyguardBouncerChanged(boolean bouncer) { - mBouncerVisible = bouncer; - update(); - } - }; - - public KeyguardMessageArea(Context context) { - super(context, null); - throw new IllegalStateException("This constructor should never be invoked"); - } - - @Inject - public KeyguardMessageArea(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, - ConfigurationController configurationController) { - this(context, attrs, Dependency.get(KeyguardUpdateMonitor.class), configurationController); - } - - public KeyguardMessageArea(Context context, AttributeSet attrs, KeyguardUpdateMonitor monitor, - ConfigurationController configurationController) { + public KeyguardMessageArea(Context context, AttributeSet attrs) { super(context, attrs); setLayerType(LAYER_TYPE_HARDWARE, null); // work around nested unclipped SaveLayer bug - monitor.registerCallback(mInfoCallback); mHandler = new Handler(Looper.myLooper()); - mConfigurationController = configurationController; onThemeChanged(); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mConfigurationController.addCallback(this); - onThemeChanged(); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mConfigurationController.removeCallback(this); - } - @Override public void setNextMessageColor(ColorStateList colorState) { mNextMessageColorState = colorState; } - @Override - public void onThemeChanged() { + void onThemeChanged() { TypedArray array = mContext.obtainStyledAttributes(new int[] { R.attr.wallpaperTextColor }); @@ -130,8 +77,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp update(); } - @Override - public void onDensityOrFontScaleChanged() { + void onDensityOrFontScaleChanged() { TypedArray array = mContext.obtainStyledAttributes(R.style.Keyguard_TextView, new int[] { android.R.attr.textSize }); @@ -177,12 +123,6 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp return messageArea; } - @Override - protected void onFinishInflate() { - boolean shouldMarquee = Dependency.get(KeyguardUpdateMonitor.class).isDeviceInteractive(); - setSelected(shouldMarquee); // This is required to ensure marquee works - } - private void securityMessageChanged(CharSequence message) { mMessage = message; update(); @@ -196,7 +136,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp update(); } - private void update() { + void update() { CharSequence status = mMessage; setVisibility(TextUtils.isEmpty(status) || !mBouncerVisible ? INVISIBLE : VISIBLE); setText(status); @@ -208,6 +148,9 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp setTextColor(colorState); } + public void setBouncerVisible(boolean bouncerVisible) { + mBouncerVisible = bouncerVisible; + } /** * Runnable used to delay accessibility announcements. diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java index 78ac4e48501be..1618e8e580559 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java @@ -19,6 +19,7 @@ package com.android.keyguard; import android.content.res.ColorStateList; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import com.android.systemui.util.ViewController; import javax.inject.Inject; @@ -28,6 +29,35 @@ public class KeyguardMessageAreaController extends ViewController configurationListenerArgumentCaptor = + ArgumentCaptor.forClass(ConfigurationListener.class); + + mMessageAreaController.onViewAttached(); + verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture()); + + mMessageAreaController.onViewDetached(); + verify(mConfigurationController).removeCallback( + eq(configurationListenerArgumentCaptor.getValue())); + } + + @Test + public void onAttachedToWindow_registersKeyguardUpdateMontiorCallback() { + ArgumentCaptor keyguardUpdateMonitorCallbackArgumentCaptor = + ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class); + + mMessageAreaController.onViewAttached(); + verify(mKeyguardUpdateMonitor).registerCallback( + keyguardUpdateMonitorCallbackArgumentCaptor.capture()); + + mMessageAreaController.onViewDetached(); + verify(mKeyguardUpdateMonitor).removeCallback( + eq(keyguardUpdateMonitorCallbackArgumentCaptor.getValue())); + } + + @Test + public void testClearsTextField() { + mMessageAreaController.setMessage(""); + verify(mKeyguardMessageArea).setMessage(""); + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java index fc7b9a4b47d13..31fb25a7a89c5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -11,65 +11,60 @@ * 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 + * limitations under the License. */ package com.android.keyguard; -import static junit.framework.Assert.assertEquals; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; +import static com.google.common.truth.Truth.assertThat; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; +import android.view.View; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.policy.ConfigurationController; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper public class KeyguardMessageAreaTest extends SysuiTestCase { - @Mock - private ConfigurationController mConfigurationController; - @Mock - private KeyguardUpdateMonitor mKeyguardUpdateMonitor; - private KeyguardMessageArea mMessageArea; + private KeyguardMessageArea mKeyguardMessageArea; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mMessageArea = new KeyguardMessageArea(mContext, null, mKeyguardUpdateMonitor, - mConfigurationController); - waitForIdleSync(); + mKeyguardMessageArea = new KeyguardMessageArea(mContext, null); + mKeyguardMessageArea.setBouncerVisible(true); } @Test - public void onAttachedToWindow_registersConfigurationCallback() { - mMessageArea.onAttachedToWindow(); - verify(mConfigurationController).addCallback(eq(mMessageArea)); - - mMessageArea.onDetachedFromWindow(); - verify(mConfigurationController).removeCallback(eq(mMessageArea)); + public void testShowsTextField() { + mKeyguardMessageArea.setVisibility(View.INVISIBLE); + mKeyguardMessageArea.setMessage("oobleck"); + assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mKeyguardMessageArea.getText()).isEqualTo("oobleck"); } @Test - public void clearFollowedByMessage_keepsMessage() { - mMessageArea.setMessage(""); - mMessageArea.setMessage("test"); - - CharSequence[] messageText = new CharSequence[1]; - messageText[0] = mMessageArea.getText(); - - assertEquals("test", messageText[0]); + public void testHiddenWhenBouncerHidden() { + mKeyguardMessageArea.setBouncerVisible(false); + mKeyguardMessageArea.setVisibility(View.INVISIBLE); + mKeyguardMessageArea.setMessage("oobleck"); + assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE); + assertThat(mKeyguardMessageArea.getText()).isEqualTo("oobleck"); } + @Test + public void testClearsTextField() { + mKeyguardMessageArea.setVisibility(View.VISIBLE); + mKeyguardMessageArea.setMessage(""); + assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE); + assertThat(mKeyguardMessageArea.getText()).isEqualTo(""); + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java index 559284ac06728..ae159c73b99fd 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java @@ -31,9 +31,7 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardDisplayManager.KeyguardPresentation; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; -import com.android.systemui.util.InjectionInflationController; import org.junit.After; import org.junit.Before; @@ -65,7 +63,6 @@ public class KeyguardPresentationTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mDependency.injectMockDependency(KeyguardUpdateMonitor.class); when(mMockKeyguardClockSwitch.getContext()).thenReturn(mContext); when(mMockKeyguardSliceView.getContext()).thenReturn(mContext); when(mMockKeyguardStatusView.getContext()).thenReturn(mContext); @@ -77,11 +74,7 @@ public class KeyguardPresentationTest extends SysuiTestCase { allowTestableLooperAsMainThread(); - InjectionInflationController inflationController = new InjectionInflationController( - SystemUIFactory.getInstance() - .getSysUIComponent() - .createViewInstanceCreatorFactory()); - mLayoutInflater = inflationController.injectable(LayoutInflater.from(mContext)); + mLayoutInflater = LayoutInflater.from(mContext); mLayoutInflater.setPrivateFactory(new LayoutInflater.Factory2() { @Override diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java index 5061eedf453a8..3b7f4b8398537 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java @@ -35,7 +35,6 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.SysuiTestCase; -import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Rule; @@ -58,8 +57,6 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { @Mock private LayoutInflater mLayoutInflater; @Mock - private InjectionInflationController mInjectionInflationController; - @Mock private KeyguardInputViewController.Factory mKeyguardSecurityViewControllerFactory; @Mock private KeyguardInputViewController mKeyguardInputViewController; @@ -74,7 +71,6 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { @Before public void setup() { - when(mInjectionInflationController.injectable(mLayoutInflater)).thenReturn(mLayoutInflater); when(mKeyguardSecurityViewControllerFactory.create( any(KeyguardInputView.class), any(SecurityMode.class), any(KeyguardSecurityCallback.class))) @@ -82,8 +78,7 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { when(mView.getWindowInsetsController()).thenReturn(mWindowInsetsController); mKeyguardSecurityViewFlipperController = new KeyguardSecurityViewFlipperController(mView, - mLayoutInflater, mInjectionInflationController, - mKeyguardSecurityViewControllerFactory); + mLayoutInflater, mKeyguardSecurityViewControllerFactory); } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java index 0431704778c3b..79ec4f2c553a6 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java @@ -24,9 +24,7 @@ import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; -import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Test; @@ -50,13 +48,7 @@ public class KeyguardStatusViewTest extends SysuiTestCase { @Before public void setUp() { allowTestableLooperAsMainThread(); - mDependency.injectMockDependency(KeyguardUpdateMonitor.class); - InjectionInflationController inflationController = new InjectionInflationController( - SystemUIFactory.getInstance() - .getSysUIComponent() - .createViewInstanceCreatorFactory()); - LayoutInflater layoutInflater = inflationController - .injectable(LayoutInflater.from(getContext())); + LayoutInflater layoutInflater = LayoutInflater.from(getContext()); mKeyguardStatusView = (KeyguardStatusView) layoutInflater.inflate(R.layout.keyguard_status_view, null); org.mockito.MockitoAnnotations.initMocks(this); From 9a80cc2ec8c627b0fc290ffc4b318382a758ed87 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Wed, 23 Sep 2020 14:01:33 +0000 Subject: [PATCH 6/7] Revert^2 "9/N Clean Up Keyguard Class Structure" b00c929394cb6bce158265af9606a8eb5a79e47a Change-Id: I42d17262a789d2eb106a924b442a9d3debcc35e4 --- .../keyguard/KeyguardAbsKeyInputView.java | 45 -------- .../KeyguardAbsKeyInputViewController.java | 28 +++-- .../android/keyguard/KeyguardInputView.java | 15 ++- .../keyguard/KeyguardInputViewController.java | 82 ++++++-------- .../com/android/keyguard/KeyguardPINView.java | 27 ----- .../keyguard/KeyguardPasswordView.java | 29 ++--- .../KeyguardPasswordViewController.java | 5 + .../android/keyguard/KeyguardPatternView.java | 68 +---------- .../KeyguardPatternViewController.java | 25 ++-- .../keyguard/KeyguardPinBasedInputView.java | 7 ++ .../keyguard/KeyguardPinViewController.java | 16 +++ .../keyguard/KeyguardSecurityContainer.java | 13 --- .../KeyguardSecurityContainerController.java | 82 ++++---------- .../keyguard/KeyguardSecurityView.java | 30 +---- .../keyguard/KeyguardSecurityViewFlipper.java | 107 +----------------- ...KeyguardSecurityViewFlipperController.java | 105 ++++++----------- .../android/keyguard/KeyguardSimPinView.java | 20 ---- .../KeyguardSimPinViewController.java | 8 +- .../android/keyguard/KeyguardSimPukView.java | 20 ---- .../KeyguardSimPukViewController.java | 13 ++- .../android/systemui/util/ViewController.java | 8 +- 21 files changed, 197 insertions(+), 556 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java index 1296990d49314..cc6df45c598f1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -17,13 +17,11 @@ package com.android.keyguard; import android.content.Context; -import android.content.res.ColorStateList; import android.util.AttributeSet; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.View; -import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; import com.android.systemui.R; @@ -31,8 +29,6 @@ import com.android.systemui.R; * Base class for PIN and password unlock screens. */ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView { - protected KeyguardSecurityCallback mCallback; - protected SecurityMessageDisplay mSecurityMessageDisplay; protected View mEcaView; protected boolean mEnableHaptics; @@ -53,19 +49,6 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView { mEnableHaptics = enableHaptics; } - @Override - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mCallback = callback; - } - - @Override - public void setLockPatternUtils(LockPatternUtils utils) { - } - - @Override - public void reset() { - } - protected abstract int getPasswordTextViewId(); protected abstract void resetState(); @@ -93,29 +76,6 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView { return mKeyDownListener != null && mKeyDownListener.onKeyDown(keyCode, event); } - @Override - public boolean needsInput() { - return false; - } - - @Override - public KeyguardSecurityCallback getCallback() { - return mCallback; - } - - @Override - public void showPromptReason(int reason) { - - } - - @Override - public void showMessage(CharSequence message, ColorStateList colorState) { - if (colorState != null) { - mSecurityMessageDisplay.setNextMessageColor(colorState); - } - mSecurityMessageDisplay.setMessage(message); - } - protected abstract int getPromptReasonStringRes(int reason); // Cause a VIRTUAL_KEY vibration @@ -127,11 +87,6 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView { } } - @Override - public boolean startDisappearAnimation(Runnable finishRunnable) { - return false; - } - public void setKeyDownListener(KeyDownListener keyDownListener) { mKeyDownListener = keyDownListener; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index 261534e06f605..53f847434dccc 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -20,6 +20,7 @@ import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL; import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED; import static com.android.keyguard.KeyguardAbsKeyInputView.MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT; +import android.content.res.ColorStateList; import android.os.AsyncTask; import android.os.CountDownTimer; import android.os.SystemClock; @@ -38,7 +39,6 @@ public abstract class KeyguardAbsKeyInputViewController { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final LockPatternUtils mLockPatternUtils; - protected final KeyguardSecurityCallback mKeyguardSecurityCallback; private final LatencyTracker mLatencyTracker; private CountDownTimer mCountdownTimer; protected KeyguardMessageAreaController mMessageAreaController; @@ -59,7 +59,7 @@ public abstract class KeyguardAbsKeyInputViewController 0) { long deadline = mLockPatternUtils.setLockoutAttemptDeadline( userId, timeoutMs); @@ -236,8 +248,8 @@ public abstract class KeyguardAbsKeyInputViewController extends ViewController implements KeyguardSecurityView { private final SecurityMode mSecurityMode; + private final KeyguardSecurityCallback mKeyguardSecurityCallback; + private boolean mPaused; + + + // 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() {} + }; protected KeyguardInputViewController(T view, SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback) { super(view); mSecurityMode = securityMode; - mView.setKeyguardCallback(keyguardSecurityCallback); - } - - @Override - public void init() { - super.init(); - mView.reset(); + mKeyguardSecurityCallback = keyguardSecurityCallback; } @Override @@ -63,63 +82,40 @@ public abstract class KeyguardInputViewController return mSecurityMode; } + protected KeyguardSecurityCallback getKeyguardSecurityCallback() { + if (mPaused) { + return mNullCallback; + } - @Override - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mView.setKeyguardCallback(callback); - } - - @Override - public void setLockPatternUtils(LockPatternUtils utils) { - mView.setLockPatternUtils(utils); + return mKeyguardSecurityCallback; } @Override public void reset() { - mView.reset(); } @Override public void onPause() { - mView.onPause(); + mPaused = true; } @Override public void onResume(int reason) { - mView.onResume(reason); - } - - @Override - public boolean needsInput() { - return mView.needsInput(); - } - - @Override - public KeyguardSecurityCallback getCallback() { - return mView.getCallback(); + mPaused = false; } @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); } @@ -129,16 +125,6 @@ public abstract class KeyguardInputViewController return mView.getTitle(); } - @Override - public boolean disallowInterceptTouch(MotionEvent event) { - return mView.disallowInterceptTouch(event); - } - - @Override - public void onStartingToHide() { - mView.onStartingToHide(); - } - /** Finds the index of this view in the suppplied parent view. */ public int getIndexIn(KeyguardSecurityViewFlipper view) { return view.indexOfChild(mView); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java index bfa187ea099b5..580d7043a2200 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java @@ -103,28 +103,6 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { new View[]{ null, mEcaView, null }}; - - View cancelBtn = findViewById(R.id.cancel_button); - if (cancelBtn != null) { - cancelBtn.setOnClickListener(view -> { - mCallback.reset(); - mCallback.onCancelClicked(); - }); - } - } - - @Override - public void onPause() { - - } - - @Override - public void onResume(int reason) { - - } - - @Override - public void showUsabilityHint() { } @Override @@ -148,11 +126,6 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { }); } - @Override - public boolean startDisappearAnimation(final Runnable finishRunnable) { - return false; - } - public boolean startDisappearAnimation(boolean needsSlowUnlockTransition, final Runnable finishRunnable) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index 3b865922503aa..aaa5efec807e5 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -16,6 +16,13 @@ package com.android.keyguard; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; + import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; @@ -30,8 +37,7 @@ import com.android.systemui.R; * Displays an alphanumeric (latin-1) key entry for the user to enter * an unlock password */ -public class KeyguardPasswordView extends KeyguardAbsKeyInputView - implements KeyguardSecurityView { +public class KeyguardPasswordView extends KeyguardAbsKeyInputView { private final int mDisappearYTranslation; @@ -68,21 +74,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView return R.id.passwordEntry; } - @Override - public void onPause() { - } - - @Override - public void onResume(int reason) { - - } - - @Override - public boolean needsInput() { - return true; - } - - @Override protected int getPromptReasonStringRes(int reason) { switch (reason) { @@ -138,10 +129,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView mPasswordEntryDisabler.setInputEnabled(enabled); } - @Override - public void showUsabilityHint() { - } - @Override public int getWrongPasswordStringId() { return R.string.kg_wrong_password; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index 52afdcd1cacb2..d34ea8c5e0181 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -155,6 +155,11 @@ public class KeyguardPasswordViewController mPasswordEntry.setOnEditorActionListener(null); } + @Override + public boolean needsInput() { + return true; + } + @Override void resetState() { mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser())); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index 8baee3b306ef0..bdcf467c24566 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -16,7 +16,6 @@ package com.android.keyguard; import android.content.Context; -import android.content.res.ColorStateList; import android.graphics.Rect; import android.os.SystemClock; import android.text.TextUtils; @@ -27,7 +26,6 @@ import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; -import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.settingslib.animation.AppearAnimationCreator; import com.android.settingslib.animation.AppearAnimationUtils; @@ -58,7 +56,6 @@ public class KeyguardPatternView extends KeyguardInputView private final Rect mLockPatternScreenBounds = new Rect(); private LockPatternView mLockPatternView; - private KeyguardSecurityCallback mCallback; /** * Keeps track of the last time we poked the wake lock during dispatching of the touch event. @@ -71,7 +68,6 @@ public class KeyguardPatternView extends KeyguardInputView KeyguardMessageArea mSecurityMessageDisplay; private View mEcaView; private ViewGroup mContainer; - private int mDisappearYTranslation; public KeyguardPatternView(Context context) { this(context, null); @@ -91,17 +87,6 @@ public class KeyguardPatternView extends KeyguardInputView (long) (125 * DISAPPEAR_MULTIPLIER_LOCKED), 1.2f /* translationScale */, 0.6f /* delayScale */, AnimationUtils.loadInterpolator( mContext, android.R.interpolator.fast_out_linear_in)); - mDisappearYTranslation = getResources().getDimensionPixelSize( - R.dimen.disappear_y_translation); - } - - @Override - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mCallback = callback; - } - - @Override - public void setLockPatternUtils(LockPatternUtils utils) { } @Override @@ -148,46 +133,11 @@ public class KeyguardPatternView extends KeyguardInputView } @Override - public void reset() { - } - - @Override - public void showUsabilityHint() { - } - - @Override - public boolean disallowInterceptTouch(MotionEvent event) { + boolean disallowInterceptTouch(MotionEvent event) { return !mLockPatternView.isEmpty() || mLockPatternScreenBounds.contains((int) event.getRawX(), (int) event.getRawY()); } - @Override - public boolean needsInput() { - return false; - } - - @Override - public void onPause() { - } - - @Override - public void onResume(int reason) { - } - - @Override - public KeyguardSecurityCallback getCallback() { - return mCallback; - } - - @Override - public void showPromptReason(int reason) { - } - - @Override - public void showMessage(CharSequence message, ColorStateList colorState) { - } - - @Override public void startAppearAnimation() { enableClipping(false); setAlpha(1f); @@ -196,12 +146,7 @@ public class KeyguardPatternView extends KeyguardInputView 0, mAppearAnimationUtils.getInterpolator()); mAppearAnimationUtils.startAnimation2d( mLockPatternView.getCellStates(), - new Runnable() { - @Override - public void run() { - enableClipping(true); - } - }, + () -> enableClipping(true), this); if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) { mAppearAnimationUtils.createAnimation(mSecurityMessageDisplay, 0, @@ -213,15 +158,6 @@ public class KeyguardPatternView extends KeyguardInputView } } - /** - * @deprecated Use {@link #startDisappearAnimation(boolean, Runnable)} - */ - @Override - public boolean startDisappearAnimation(Runnable finishRunnable) { - // TODO(b/166448040): remove this when possible - return false; - } - public boolean startDisappearAnimation(boolean needsSlowUnlockTransition, final Runnable finishRunnable) { float durationMultiplier = needsSlowUnlockTransition ? DISAPPEAR_MULTIPLIER_LOCKED : 1f; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 38b535049fb4c..3db9db7be00c6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -54,13 +54,12 @@ public class KeyguardPatternViewController private KeyguardMessageAreaController mMessageAreaController; private LockPatternView mLockPatternView; private CountDownTimer mCountdownTimer; - private KeyguardSecurityCallback mCallback; private AsyncTask mPendingLockCheck; private EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() { @Override public void onEmergencyButtonClickedWhenInCall() { - mCallback.reset(); + getKeyguardSecurityCallback().reset(); } }; @@ -88,8 +87,8 @@ public class KeyguardPatternViewController @Override public void onPatternCellAdded(List pattern) { - mCallback.userActivity(); - mCallback.onUserInput(); + getKeyguardSecurityCallback().userActivity(); + getKeyguardSecurityCallback().onUserInput(); } @Override @@ -141,8 +140,8 @@ public class KeyguardPatternViewController } }); if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { - mCallback.userActivity(); - mCallback.onUserInput(); + getKeyguardSecurityCallback().userActivity(); + getKeyguardSecurityCallback().onUserInput(); } } @@ -150,15 +149,15 @@ public class KeyguardPatternViewController boolean isValidPattern) { boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId; if (matched) { - mCallback.reportUnlockAttempt(userId, true, 0); + getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0); if (dismissKeyguard) { mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct); - mCallback.dismiss(true, userId); + getKeyguardSecurityCallback().dismiss(true, userId); } } else { mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); if (isValidPattern) { - mCallback.reportUnlockAttempt(userId, false, timeoutMs); + getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs); if (timeoutMs > 0) { long deadline = mLockPatternUtils.setLockoutAttemptDeadline( userId, timeoutMs); @@ -213,8 +212,8 @@ public class KeyguardPatternViewController View cancelBtn = mView.findViewById(R.id.cancel_button); if (cancelBtn != null) { cancelBtn.setOnClickListener(view -> { - mCallback.reset(); - mCallback.onCancelClicked(); + getKeyguardSecurityCallback().reset(); + getKeyguardSecurityCallback().onCancelClicked(); }); } } @@ -269,8 +268,8 @@ public class KeyguardPatternViewController } @Override - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mCallback = callback; + public boolean needsInput() { + return false; } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index e579380fc8d59..7fa43116a7b1d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -16,6 +16,13 @@ package com.android.keyguard; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; + import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java index 625ab5214da15..6769436be8ef5 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java @@ -16,9 +16,12 @@ package com.android.keyguard; +import android.view.View; + import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; public class KeyguardPinViewController extends KeyguardPinBasedInputViewController { @@ -36,6 +39,19 @@ public class KeyguardPinViewController mKeyguardUpdateMonitor = keyguardUpdateMonitor; } + @Override + protected void onViewAttached() { + super.onViewAttached(); + + View cancelBtn = mView.findViewById(R.id.cancel_button); + if (cancelBtn != null) { + cancelBtn.setOnClickListener(view -> { + getKeyguardSecurityCallback().reset(); + getKeyguardSecurityCallback().onCancelClicked(); + }); + } + } + @Override void resetState() { super.resetState(); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 07f70c14b74ab..b62ea6bc2ff63 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -395,10 +395,6 @@ public class KeyguardSecurityContainer extends FrameLayout { mSecurityViewFlipper = findViewById(R.id.view_flipper); } - public void setLockPatternUtils(LockPatternUtils utils) { - mSecurityViewFlipper.setLockPatternUtils(utils); - } - @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { @@ -498,16 +494,7 @@ public class KeyguardSecurityContainer extends FrameLayout { } public void reset() { - mSecurityViewFlipper.reset(); mDisappearAnimRunning = false; } - - public KeyguardSecurityCallback getCallback() { - return mSecurityViewFlipper.getCallback(); - } - - 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 2c7dce6e43021..64676e55b0382 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -50,9 +50,6 @@ import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.ViewController; -import java.util.ArrayList; -import java.util.List; - import javax.inject.Inject; /** Controller for {@link KeyguardSecurityContainer} */ @@ -71,7 +68,6 @@ public class KeyguardSecurityContainerController extends ViewController mChildren = new ArrayList<>(); private SecurityCallback mSecurityCallback; private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid; @@ -137,28 +133,6 @@ public class KeyguardSecurityContainerController extends ViewController oldView = getCurrentSecurityController(); // Emulate Activity life cycle if (oldView != null) { oldView.onPause(); - oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view } + + KeyguardInputViewController newView = changeSecurityMode(securityMode); if (newView != null) { newView.onResume(KeyguardSecurityView.VIEW_REVEALED); - newView.setKeyguardCallback(mKeyguardSecurityCallback); mSecurityViewFlipperController.show(newView); } - mCurrentSecurityMode = securityMode; mSecurityCallback.onSecurityModeChanged( securityMode, newView != null && newView.needsInput()); } @@ -470,28 +440,14 @@ public class KeyguardSecurityContainerController extends ViewController getCurrentSecurityController() { return mSecurityViewFlipperController - .getSecurityView(securityMode, mKeyguardSecurityCallback); + .getSecurityView(mCurrentSecurityMode, mKeyguardSecurityCallback); + } + + private KeyguardInputViewController changeSecurityMode( + SecurityMode securityMode) { + mCurrentSecurityMode = securityMode; + return getCurrentSecurityController(); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java index 43cef3acf1479..ac00e9453c975 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java @@ -18,11 +18,9 @@ package com.android.keyguard; import android.content.res.ColorStateList; import android.view.MotionEvent; -import com.android.internal.widget.LockPatternUtils; - public interface KeyguardSecurityView { - static public final int SCREEN_ON = 1; - static public final int VIEW_REVEALED = 2; + int SCREEN_ON = 1; + int VIEW_REVEALED = 2; int PROMPT_REASON_NONE = 0; @@ -62,18 +60,6 @@ public interface KeyguardSecurityView { */ int PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT = 7; - /** - * Interface back to keyguard to tell it when security - * @param callback - */ - void setKeyguardCallback(KeyguardSecurityCallback callback); - - /** - * Set {@link LockPatternUtils} object. Useful for providing a mock interface. - * @param utils - */ - void setLockPatternUtils(LockPatternUtils utils); - /** * Reset the view and prepare to take input. This should do things like clearing the * password or pattern and clear error messages. @@ -100,12 +86,6 @@ public interface KeyguardSecurityView { */ boolean needsInput(); - /** - * Get {@link KeyguardSecurityCallback} for the given object - * @return KeyguardSecurityCallback - */ - KeyguardSecurityCallback getCallback(); - /** * Show a string explaining why the security view needs to be solved. * @@ -122,12 +102,6 @@ public interface KeyguardSecurityView { */ void showMessage(CharSequence message, ColorStateList colorState); - /** - * Instruct the view to show usability hints, if any. - * - */ - void showUsabilityHint(); - /** * Starts the animation which should run when the security view appears. */ diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java index 24da3ad46f234..b8439af6daaad 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java @@ -18,7 +18,6 @@ package com.android.keyguard; import android.annotation.NonNull; import android.content.Context; -import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.Rect; import android.util.AttributeSet; @@ -31,7 +30,6 @@ import android.view.ViewHierarchyEncoder; import android.widget.FrameLayout; import android.widget.ViewFlipper; -import com.android.internal.widget.LockPatternUtils; import com.android.systemui.R; /** @@ -39,7 +37,7 @@ import com.android.systemui.R; * we can emulate {@link android.view.WindowManager.LayoutParams#FLAG_SLIPPERY} within a view * hierarchy. */ -public class KeyguardSecurityViewFlipper extends ViewFlipper implements KeyguardSecurityView { +public class KeyguardSecurityViewFlipper extends ViewFlipper { private static final String TAG = "KeyguardSecurityViewFlipper"; private static final boolean DEBUG = KeyguardConstants.DEBUG; @@ -69,111 +67,16 @@ public class KeyguardSecurityViewFlipper extends ViewFlipper implements Keyguard return result; } - KeyguardSecurityView getSecurityView() { + KeyguardInputView getSecurityView() { View child = getChildAt(getDisplayedChild()); - if (child instanceof KeyguardSecurityView) { - return (KeyguardSecurityView) child; + if (child instanceof KeyguardInputView) { + return (KeyguardInputView) child; } return null; } - @Override - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.setKeyguardCallback(callback); - } - } - - @Override - public void setLockPatternUtils(LockPatternUtils utils) { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.setLockPatternUtils(utils); - } - } - - @Override - public void reset() { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.reset(); - } - } - - @Override - public void onPause() { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.onPause(); - } - } - - @Override - public void onResume(int reason) { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.onResume(reason); - } - } - - @Override - public boolean needsInput() { - KeyguardSecurityView ksv = getSecurityView(); - return (ksv != null) ? ksv.needsInput() : false; - } - - @Override - public KeyguardSecurityCallback getCallback() { - KeyguardSecurityView ksv = getSecurityView(); - return (ksv != null) ? ksv.getCallback() : null; - } - - @Override - public void showPromptReason(int reason) { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.showPromptReason(reason); - } - } - - @Override - public void showMessage(CharSequence message, ColorStateList colorState) { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.showMessage(message, colorState); - } - } - - @Override - public void showUsabilityHint() { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.showUsabilityHint(); - } - } - - @Override - public void startAppearAnimation() { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.startAppearAnimation(); - } - } - - @Override - public boolean startDisappearAnimation(Runnable finishRunnable) { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - return ksv.startDisappearAnimation(finishRunnable); - } else { - return false; - } - } - - @Override public CharSequence getTitle() { - KeyguardSecurityView ksv = getSecurityView(); + KeyguardInputView ksv = getSecurityView(); if (ksv != null) { return ksv.getTitle(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java index 73adff94650a9..49530355a6fb5 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java @@ -16,12 +16,10 @@ package com.android.keyguard; -import android.content.res.ColorStateList; import android.util.Log; import android.view.LayoutInflater; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardInputViewController.Factory; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.dagger.KeyguardBouncerScope; @@ -38,12 +36,13 @@ import javax.inject.Inject; */ @KeyguardBouncerScope public class KeyguardSecurityViewFlipperController - extends ViewController implements KeyguardSecurityView { + extends ViewController { private static final boolean DEBUG = KeyguardConstants.DEBUG; private static final String TAG = "KeyguardSecurityView"; - private final List mChildren = new ArrayList<>(); + private final List> mChildren = + new ArrayList<>(); private final LayoutInflater mLayoutInflater; private final Factory mKeyguardSecurityViewControllerFactory; @@ -66,80 +65,19 @@ public class KeyguardSecurityViewFlipperController } - @Override - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mView.setKeyguardCallback(callback); - } - - @Override - public void setLockPatternUtils(LockPatternUtils utils) { - mView.setLockPatternUtils(utils); - } - - @Override public void reset() { - for (KeyguardInputViewController child : mChildren) { + for (KeyguardInputViewController child : mChildren) { child.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(); - } - @VisibleForTesting - KeyguardInputViewController getSecurityView(SecurityMode securityMode, + KeyguardInputViewController getSecurityView(SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback) { - KeyguardInputViewController childController = null; - for (KeyguardInputViewController mChild : mChildren) { - if (mChild.getSecurityMode() == securityMode) { - childController = mChild; + KeyguardInputViewController childController = null; + for (KeyguardInputViewController child : mChildren) { + if (child.getSecurityMode() == securityMode) { + childController = child; break; } } @@ -162,6 +100,11 @@ public class KeyguardSecurityViewFlipperController } } + if (childController == null) { + childController = new NullKeyguardInputViewController( + securityMode, keyguardSecurityCallback); + } + return childController; } @@ -178,10 +121,28 @@ public class KeyguardSecurityViewFlipperController } /** Makes the supplied child visible if it is contained win this view, */ - public void show(KeyguardInputViewController childController) { + public void show(KeyguardInputViewController childController) { int index = childController.getIndexIn(mView); if (index != -1) { mView.setDisplayedChild(index); } } + + private static class NullKeyguardInputViewController + extends KeyguardInputViewController { + protected NullKeyguardInputViewController(SecurityMode securityMode, + KeyguardSecurityCallback keyguardSecurityCallback) { + super(null, securityMode, keyguardSecurityCallback); + } + + @Override + public boolean needsInput() { + return false; + } + + @Override + public void onStartingToHide() { + + } + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java index 202971d2a0099..c0f9ce794628b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java @@ -68,31 +68,11 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { } } - @Override - public void onPause() { - - } - - @Override - public void onResume(int reason) { - - } - - @Override - public void showUsabilityHint() { - - } - @Override public void startAppearAnimation() { // noop. } - @Override - public boolean startDisappearAnimation(Runnable finishRunnable) { - return false; - } - @Override public CharSequence getTitle() { return getContext().getString( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java index 3c29058e0afc2..cc8bf4f2d0289 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java @@ -106,7 +106,7 @@ public class KeyguardSimPinViewController @Override public boolean startDisappearAnimation(Runnable finishRunnable) { - return mView.startDisappearAnimation(finishRunnable); + return false; } @Override @@ -137,7 +137,7 @@ public class KeyguardSimPinViewController mMessageAreaController.setMessage( com.android.systemui.R.string.kg_invalid_sim_pin_hint); mView.resetPasswordText(true /* animate */, true /* announce */); - mKeyguardSecurityCallback.userActivity(); + getKeyguardSecurityCallback().userActivity(); return; } @@ -159,7 +159,7 @@ public class KeyguardSimPinViewController mKeyguardUpdateMonitor.reportSimUnlocked(mSubId); mRemainingAttempts = -1; mShowDefaultMessage = true; - mKeyguardSecurityCallback.dismiss( + getKeyguardSecurityCallback().dismiss( true, KeyguardUpdateMonitor.getCurrentUser()); } else { mShowDefaultMessage = false; @@ -186,7 +186,7 @@ public class KeyguardSimPinViewController + " attemptsRemaining=" + result.getAttemptsRemaining()); } } - mKeyguardSecurityCallback.userActivity(); + getKeyguardSecurityCallback().userActivity(); mCheckSimPinThread = null; }); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java index 932d9b966fa39..0d72c93e90419 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java @@ -16,7 +16,6 @@ package com.android.keyguard; -import android.app.ProgressDialog; import android.content.Context; import android.util.AttributeSet; import android.util.Log; @@ -31,8 +30,6 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { private static final boolean DEBUG = KeyguardConstants.DEBUG; public static final String TAG = "KeyguardSimPukView"; - private ProgressDialog mSimUnlockProgressDialog = null; - public KeyguardSimPukView(Context context) { this(context, null); } @@ -89,23 +86,6 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { } } - @Override - public void showUsabilityHint() { - } - - @Override - public void onPause() { - // dismiss the dialog. - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.dismiss(); - mSimUnlockProgressDialog = null; - } - } - - @Override - public void onResume(int reason) { - } - @Override public void startAppearAnimation() { // noop. diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java index 9b2166b044155..a87374939ba68 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java @@ -69,7 +69,7 @@ public class KeyguardSimPukViewController if (simState == TelephonyManager.SIM_STATE_READY) { mRemainingAttempts = -1; mShowDefaultMessage = true; - mKeyguardSecurityCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser()); + getKeyguardSecurityCallback().dismiss(true, KeyguardUpdateMonitor.getCurrentUser()); } else { resetState(); } @@ -273,7 +273,7 @@ public class KeyguardSimPukViewController mRemainingAttempts = -1; mShowDefaultMessage = true; - mKeyguardSecurityCallback.dismiss( + getKeyguardSecurityCallback().dismiss( true, KeyguardUpdateMonitor.getCurrentUser()); } else { mShowDefaultMessage = false; @@ -362,6 +362,15 @@ public class KeyguardSimPukViewController return mRemainingAttemptsDialog; } + @Override + public void onPause() { + // dismiss the dialog. + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.dismiss(); + mSimUnlockProgressDialog = null; + } + } + /** * Since the IPC can block, we want to run the request in a separate thread * with a callback. diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java index f30472f75d298..c7aa780fcacb5 100644 --- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java +++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java @@ -67,10 +67,12 @@ public abstract class ViewController { } mInited = true; - if (mView.isAttachedToWindow()) { - mOnAttachStateListener.onViewAttachedToWindow(mView); + if (mView != null) { + if (mView.isAttachedToWindow()) { + mOnAttachStateListener.onViewAttachedToWindow(mView); + } + mView.addOnAttachStateChangeListener(mOnAttachStateListener); } - mView.addOnAttachStateChangeListener(mOnAttachStateListener); } /** From 28822be53301c76b08ccc8b815c1a56c44e085b6 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Thu, 24 Sep 2020 14:34:57 -0400 Subject: [PATCH 7/7] 10/N Ensure KeyguardSecurityContainer always has Callback This passes the SecurityCallback directly into the KeyguardSecurityContainer's constructor, rather than setting it during on-attach. Fixes: 169231892 Test: atest SystemUITests && manual Change-Id: Ia9adf399e299768b3b8a70822cfda662a54d803b --- .../keyguard/KeyguardHostViewController.java | 9 +-- .../KeyguardSecurityContainerController.java | 56 ++++++++++++++++--- .../KeyguardHostViewControllerTest.java | 15 +++-- ...yguardSecurityContainerControllerTest.java | 7 +-- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java index 9ffa658da0e89..351369c51364e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java @@ -163,16 +163,18 @@ public class KeyguardHostViewController extends ViewController @Inject public KeyguardHostViewController(KeyguardHostView view, KeyguardUpdateMonitor keyguardUpdateMonitor, - KeyguardSecurityContainerController keyguardSecurityContainerController, AudioManager audioManager, TelephonyManager telephonyManager, - ViewMediatorCallback viewMediatorCallback) { + ViewMediatorCallback viewMediatorCallback, + KeyguardSecurityContainerController.Factory + keyguardSecurityContainerControllerFactory) { super(view); mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mKeyguardSecurityContainerController = keyguardSecurityContainerController; mAudioManager = audioManager; mTelephonyManager = telephonyManager; mViewMediatorCallback = viewMediatorCallback; + mKeyguardSecurityContainerController = keyguardSecurityContainerControllerFactory.create( + mSecurityCallback); } /** Initialize the Controller. */ @@ -188,7 +190,6 @@ public class KeyguardHostViewController extends ViewController mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput()); mKeyguardUpdateMonitor.registerCallback(mUpdateCallback); mView.setOnKeyListener(mOnKeyListener); - mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback); mKeyguardSecurityContainerController.showPrimarySecurityScreen(false); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 64676e55b0382..1c23605a8516b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -68,8 +68,8 @@ public class KeyguardSecurityContainerController extends ViewController