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 android.view.View;
20 
21 import com.android.internal.util.LatencyTracker;
22 import com.android.internal.widget.LockPatternUtils;
23 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
24 import com.android.systemui.R;
25 import com.android.systemui.classifier.FalsingCollector;
26 import com.android.systemui.flags.FeatureFlags;
27 import com.android.systemui.flags.Flags;
28 import com.android.systemui.statusbar.policy.DevicePostureController;
29 
30 public class KeyguardPinViewController
31         extends KeyguardPinBasedInputViewController<KeyguardPINView> {
32     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
33     private final DevicePostureController mPostureController;
34     private final DevicePostureController.Callback mPostureCallback = posture ->
35             mView.onDevicePostureChanged(posture);
36     private LockPatternUtils mLockPatternUtils;
37     private final FeatureFlags mFeatureFlags;
38     private static final int DEFAULT_PIN_LENGTH = 6;
39     private static final int MIN_FAILED_PIN_ATTEMPTS = 5;
40     private NumPadButton mBackspaceKey;
41     private View mOkButton = mView.findViewById(R.id.key_enter);
42 
43     private long mPinLength;
44 
45     private boolean mDisabledAutoConfirmation;
46 
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)47     protected KeyguardPinViewController(KeyguardPINView view,
48             KeyguardUpdateMonitor keyguardUpdateMonitor,
49             SecurityMode securityMode, LockPatternUtils lockPatternUtils,
50             KeyguardSecurityCallback keyguardSecurityCallback,
51             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
52             LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
53             EmergencyButtonController emergencyButtonController,
54             FalsingCollector falsingCollector,
55             DevicePostureController postureController,
56             FeatureFlags featureFlags) {
57         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
58                 messageAreaControllerFactory, latencyTracker, liftToActivateListener,
59                 emergencyButtonController, falsingCollector, featureFlags);
60         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
61         mPostureController = postureController;
62         mLockPatternUtils = lockPatternUtils;
63         mFeatureFlags = featureFlags;
64         mBackspaceKey = view.findViewById(R.id.delete_button);
65         mPinLength = mLockPatternUtils.getPinLength(KeyguardUpdateMonitor.getCurrentUser());
66     }
67 
68     @Override
onViewAttached()69     protected void onViewAttached() {
70         super.onViewAttached();
71 
72         View cancelBtn = mView.findViewById(R.id.cancel_button);
73         if (cancelBtn != null) {
74             cancelBtn.setOnClickListener(view -> {
75                 getKeyguardSecurityCallback().reset();
76                 getKeyguardSecurityCallback().onCancelClicked();
77             });
78         }
79         mPasswordEntry.setUserActivityListener(this::onUserInput);
80         mView.onDevicePostureChanged(mPostureController.getDevicePosture());
81         mPostureController.addCallback(mPostureCallback);
82         if (mFeatureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)) {
83             mPasswordEntry.setUsePinShapes(true);
84             updateAutoConfirmationState();
85         }
86     }
87 
onUserInput()88     protected void onUserInput() {
89         super.onUserInput();
90         if (isAutoPinConfirmEnabledInSettings()) {
91             updateAutoConfirmationState();
92             if (mPasswordEntry.getText().length() == mPinLength
93                     && mOkButton.getVisibility() == View.INVISIBLE) {
94                 verifyPasswordAndUnlock();
95             }
96         }
97     }
98 
99     @Override
onViewDetached()100     protected void onViewDetached() {
101         super.onViewDetached();
102         mPostureController.removeCallback(mPostureCallback);
103     }
104 
105     @Override
startAppearAnimation()106     public void startAppearAnimation() {
107         super.startAppearAnimation();
108     }
109 
110     @Override
startDisappearAnimation(Runnable finishRunnable)111     public boolean startDisappearAnimation(Runnable finishRunnable) {
112         return mView.startDisappearAnimation(
113                 mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
114     }
115 
116     @Override
handleAttemptLockout(long elapsedRealtimeDeadline)117     protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
118         super.handleAttemptLockout(elapsedRealtimeDeadline);
119         updateAutoConfirmationState();
120     }
121 
updateAutoConfirmationState()122     private void updateAutoConfirmationState() {
123         mDisabledAutoConfirmation = mLockPatternUtils.getCurrentFailedPasswordAttempts(
124                 KeyguardUpdateMonitor.getCurrentUser()) >= MIN_FAILED_PIN_ATTEMPTS;
125         updateOKButtonVisibility();
126         updateBackSpaceVisibility();
127         updatePinHinting();
128     }
129 
130     /**
131      * Updates the visibility of the OK button for auto confirm feature
132      */
updateOKButtonVisibility()133     private void updateOKButtonVisibility() {
134         if (isAutoPinConfirmEnabledInSettings() && !mDisabledAutoConfirmation) {
135             mOkButton.setVisibility(View.INVISIBLE);
136         } else {
137             mOkButton.setVisibility(View.VISIBLE);
138         }
139     }
140 
141     /**
142      * Updates the visibility and the enabled state of the backspace.
143      * Visibility changes are only for auto confirmation configuration.
144      */
updateBackSpaceVisibility()145     private void updateBackSpaceVisibility() {
146         boolean isAutoConfirmation = isAutoPinConfirmEnabledInSettings();
147         mBackspaceKey.setTransparentMode(/* isTransparentMode= */
148                 isAutoConfirmation && !mDisabledAutoConfirmation);
149         if (isAutoConfirmation) {
150             if (mPasswordEntry.getText().length() > 0
151                     || mDisabledAutoConfirmation) {
152                 mBackspaceKey.setVisibility(View.VISIBLE);
153             } else {
154                 mBackspaceKey.setVisibility(View.INVISIBLE);
155             }
156         }
157     }
158     /** Updates whether to use pin hinting or not. */
updatePinHinting()159     void updatePinHinting() {
160         mPasswordEntry.setIsPinHinting(isAutoPinConfirmEnabledInSettings() && isPinHinting()
161                 && !mDisabledAutoConfirmation);
162     }
163 
164     /**
165      * Responsible for identifying if PIN hinting is to be enabled or not
166      */
isPinHinting()167     private boolean isPinHinting() {
168         return mPinLength == DEFAULT_PIN_LENGTH;
169     }
170 
171     /**
172      * Responsible for identifying if auto confirm is enabled or not in Settings and
173      * a valid PIN_LENGTH is stored on the device (though the latter check is only to make it more
174      * robust since we only allow enabling PIN confirmation if the user has a valid PIN length
175      * saved on device)
176      */
isAutoPinConfirmEnabledInSettings()177     private boolean isAutoPinConfirmEnabledInSettings() {
178         //Checks if user has enabled the auto confirm in Settings
179         return mLockPatternUtils.isAutoPinConfirmEnabled(KeyguardUpdateMonitor.getCurrentUser())
180                 && mPinLength != LockPatternUtils.PIN_LENGTH_UNAVAILABLE;
181     }
182 }
183