1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.keyguard;
18 
19 import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
20 
21 import android.view.View;
22 
23 import com.android.internal.logging.UiEvent;
24 import com.android.internal.logging.UiEventLogger;
25 import com.android.internal.util.LatencyTracker;
26 import com.android.internal.widget.LockPatternUtils;
27 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
28 import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
29 import com.android.systemui.classifier.FalsingCollector;
30 import com.android.systemui.flags.FeatureFlags;
31 import com.android.systemui.flags.Flags;
32 import com.android.systemui.res.R;
33 import com.android.systemui.statusbar.policy.DevicePostureController;
34 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
35 
36 public class KeyguardPinViewController
37         extends KeyguardPinBasedInputViewController<KeyguardPINView> {
38     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
39     private final DevicePostureController mPostureController;
40     private final DevicePostureController.Callback mPostureCallback = posture ->
41             mView.onDevicePostureChanged(posture);
42     private LockPatternUtils mLockPatternUtils;
43     private final FeatureFlags mFeatureFlags;
44     private static final int DEFAULT_PIN_LENGTH = 6;
45     private static final int MIN_FAILED_PIN_ATTEMPTS = 5;
46     private NumPadButton mBackspaceKey;
47     private View mOkButton = mView.findViewById(R.id.key_enter);
48 
49     private long mPinLength;
50     private final UiEventLogger mUiEventLogger;
51 
52     private boolean mDisabledAutoConfirmation;
53 
KeyguardPinViewController(KeyguardPINView view, KeyguardUpdateMonitor keyguardUpdateMonitor, SecurityMode securityMode, LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, EmergencyButtonController emergencyButtonController, FalsingCollector falsingCollector, DevicePostureController postureController, FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, UiEventLogger uiEventLogger, KeyguardKeyboardInteractor keyguardKeyboardInteractor)54     protected KeyguardPinViewController(KeyguardPINView view,
55             KeyguardUpdateMonitor keyguardUpdateMonitor,
56             SecurityMode securityMode, LockPatternUtils lockPatternUtils,
57             KeyguardSecurityCallback keyguardSecurityCallback,
58             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
59             LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
60             EmergencyButtonController emergencyButtonController,
61             FalsingCollector falsingCollector,
62             DevicePostureController postureController, FeatureFlags featureFlags,
63             SelectedUserInteractor selectedUserInteractor, UiEventLogger uiEventLogger,
64             KeyguardKeyboardInteractor keyguardKeyboardInteractor) {
65         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
66                 messageAreaControllerFactory, latencyTracker, liftToActivateListener,
67                 emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor,
68                 keyguardKeyboardInteractor);
69         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
70         mPostureController = postureController;
71         mLockPatternUtils = lockPatternUtils;
72         mFeatureFlags = featureFlags;
73         view.setIsLockScreenLandscapeEnabled(mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE));
74         mBackspaceKey = view.findViewById(R.id.delete_button);
75         mPinLength = mLockPatternUtils.getPinLength(selectedUserInteractor.getSelectedUserId());
76         mUiEventLogger = uiEventLogger;
77     }
78 
79     @Override
onViewAttached()80     protected void onViewAttached() {
81         super.onViewAttached();
82 
83         View cancelBtn = mView.findViewById(R.id.cancel_button);
84         if (cancelBtn != null) {
85             cancelBtn.setOnClickListener(view -> {
86                 getKeyguardSecurityCallback().reset();
87                 getKeyguardSecurityCallback().onCancelClicked();
88             });
89         }
90         mPasswordEntry.setUserActivityListener(this::onUserInput);
91         mView.onDevicePostureChanged(mPostureController.getDevicePosture());
92         mPostureController.addCallback(mPostureCallback);
93         if (mFeatureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)) {
94             mPasswordEntry.setUsePinShapes(true);
95             updateAutoConfirmationState();
96         }
97     }
98 
onUserInput()99     protected void onUserInput() {
100         super.onUserInput();
101         if (isAutoPinConfirmEnabledInSettings()) {
102             updateAutoConfirmationState();
103             if (mPasswordEntry.getText().length() == mPinLength
104                     && mOkButton.getVisibility() == View.INVISIBLE) {
105                 mUiEventLogger.log(PinBouncerUiEvent.ATTEMPT_UNLOCK_WITH_AUTO_CONFIRM_FEATURE);
106                 verifyPasswordAndUnlock();
107             }
108         }
109     }
110 
111     @Override
onViewDetached()112     protected void onViewDetached() {
113         super.onViewDetached();
114         mPostureController.removeCallback(mPostureCallback);
115     }
116 
117     @Override
startAppearAnimation()118     public void startAppearAnimation() {
119         super.startAppearAnimation();
120     }
121 
122     @Override
startDisappearAnimation(Runnable finishRunnable)123     public boolean startDisappearAnimation(Runnable finishRunnable) {
124         return mView.startDisappearAnimation(
125                 mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
126     }
127 
128     @Override
handleAttemptLockout(long elapsedRealtimeDeadline)129     protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
130         super.handleAttemptLockout(elapsedRealtimeDeadline);
131         updateAutoConfirmationState();
132     }
133 
updateAutoConfirmationState()134     private void updateAutoConfirmationState() {
135         mDisabledAutoConfirmation = mLockPatternUtils.getCurrentFailedPasswordAttempts(
136                 mSelectedUserInteractor.getSelectedUserId()) >= MIN_FAILED_PIN_ATTEMPTS;
137         updateOKButtonVisibility();
138         updateBackSpaceVisibility();
139         updatePinHinting();
140     }
141 
142     /**
143      * Updates the visibility of the OK button for auto confirm feature
144      */
updateOKButtonVisibility()145     private void updateOKButtonVisibility() {
146         if (isAutoPinConfirmEnabledInSettings() && !mDisabledAutoConfirmation) {
147             mOkButton.setVisibility(View.INVISIBLE);
148         } else {
149             mOkButton.setVisibility(View.VISIBLE);
150         }
151     }
152 
153     /**
154      * Updates the visibility and the enabled state of the backspace.
155      * Visibility changes are only for auto confirmation configuration.
156      */
updateBackSpaceVisibility()157     private void updateBackSpaceVisibility() {
158         boolean isAutoConfirmation = isAutoPinConfirmEnabledInSettings();
159         mBackspaceKey.setTransparentMode(/* isTransparentMode= */
160                 isAutoConfirmation && !mDisabledAutoConfirmation);
161         if (isAutoConfirmation) {
162             if (mPasswordEntry.getText().length() > 0
163                     || mDisabledAutoConfirmation) {
164                 mBackspaceKey.setVisibility(View.VISIBLE);
165             } else {
166                 mBackspaceKey.setVisibility(View.INVISIBLE);
167             }
168         }
169     }
170     /** Updates whether to use pin hinting or not. */
updatePinHinting()171     void updatePinHinting() {
172         mPasswordEntry.setIsPinHinting(isAutoPinConfirmEnabledInSettings() && isPinHinting()
173                 && !mDisabledAutoConfirmation);
174     }
175 
176     /**
177      * Responsible for identifying if PIN hinting is to be enabled or not
178      */
isPinHinting()179     private boolean isPinHinting() {
180         return mPinLength == DEFAULT_PIN_LENGTH;
181     }
182 
183     /**
184      * Responsible for identifying if auto confirm is enabled or not in Settings and
185      * a valid PIN_LENGTH is stored on the device (though the latter check is only to make it more
186      * robust since we only allow enabling PIN confirmation if the user has a valid PIN length
187      * saved on device)
188      */
isAutoPinConfirmEnabledInSettings()189     private boolean isAutoPinConfirmEnabledInSettings() {
190         //Checks if user has enabled the auto confirm in Settings
191         return mLockPatternUtils.isAutoPinConfirmEnabled(
192                 mSelectedUserInteractor.getSelectedUserId())
193                 && mPinLength != LockPatternUtils.PIN_LENGTH_UNAVAILABLE;
194     }
195 
196     /** UI Events for the auto confirmation feature in*/
197     enum PinBouncerUiEvent implements UiEventLogger.UiEventEnum {
198         @UiEvent(doc = "Attempting to unlock the device with the auto confirm feature.")
199         ATTEMPT_UNLOCK_WITH_AUTO_CONFIRM_FEATURE(1547);
200 
201         private final int mId;
202 
PinBouncerUiEvent(int id)203         PinBouncerUiEvent(int id) {
204             mId = id;
205         }
206 
207         @Override
getId()208         public int getId() {
209             return mId;
210         }
211     }
212 }
213