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.KeyEvent;
20 import android.view.MotionEvent;
21 import android.view.View;
22 import android.view.View.OnKeyListener;
23 import android.view.View.OnTouchListener;
24 
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.systemui.R;
29 import com.android.systemui.classifier.FalsingCollector;
30 
31 public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinBasedInputView>
32         extends KeyguardAbsKeyInputViewController<T> {
33 
34     private final LiftToActivateListener mLiftToActivateListener;
35     private final FalsingCollector mFalsingCollector;
36     protected PasswordTextView mPasswordEntry;
37 
38     private final OnKeyListener mOnKeyListener = (v, keyCode, event) -> {
39         if (event.getAction() == KeyEvent.ACTION_DOWN) {
40             return mView.onKeyDown(keyCode, event);
41         }
42         return false;
43     };
44 
45     private final OnTouchListener mActionButtonTouchListener = (v, event) -> {
46         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
47             mView.doHapticKeyClick();
48         }
49         return false;
50     };
51 
KeyguardPinBasedInputViewController(T view, KeyguardUpdateMonitor keyguardUpdateMonitor, SecurityMode securityMode, LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, EmergencyButtonController emergencyButtonController, FalsingCollector falsingCollector)52     protected KeyguardPinBasedInputViewController(T view,
53             KeyguardUpdateMonitor keyguardUpdateMonitor,
54             SecurityMode securityMode,
55             LockPatternUtils lockPatternUtils,
56             KeyguardSecurityCallback keyguardSecurityCallback,
57             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
58             LatencyTracker latencyTracker,
59             LiftToActivateListener liftToActivateListener,
60             EmergencyButtonController emergencyButtonController,
61             FalsingCollector falsingCollector) {
62         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
63                 messageAreaControllerFactory, latencyTracker, falsingCollector,
64                 emergencyButtonController);
65         mLiftToActivateListener = liftToActivateListener;
66         mFalsingCollector = falsingCollector;
67         mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
68     }
69 
70     @Override
onViewAttached()71     protected void onViewAttached() {
72         super.onViewAttached();
73 
74         for (NumPadKey button: mView.getButtons()) {
75             button.setOnTouchListener((v, event) -> {
76                 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
77                     mFalsingCollector.avoidGesture();
78                 }
79                 return false;
80             });
81         }
82         mPasswordEntry.setOnKeyListener(mOnKeyListener);
83         mPasswordEntry.setUserActivityListener(this::onUserInput);
84 
85         View deleteButton = mView.findViewById(R.id.delete_button);
86         deleteButton.setOnTouchListener(mActionButtonTouchListener);
87         deleteButton.setOnClickListener(v -> {
88             // check for time-based lockouts
89             if (mPasswordEntry.isEnabled()) {
90                 mPasswordEntry.deleteLastChar();
91             }
92         });
93         deleteButton.setOnLongClickListener(v -> {
94             // check for time-based lockouts
95             if (mPasswordEntry.isEnabled()) {
96                 mView.resetPasswordText(true /* animate */, true /* announce */);
97             }
98             mView.doHapticKeyClick();
99             return true;
100         });
101 
102         View okButton = mView.findViewById(R.id.key_enter);
103         if (okButton != null) {
104             okButton.setOnTouchListener(mActionButtonTouchListener);
105             okButton.setOnClickListener(new View.OnClickListener() {
106                 @Override
107                 public void onClick(View v) {
108                     if (mPasswordEntry.isEnabled()) {
109                         verifyPasswordAndUnlock();
110                     }
111                 }
112             });
113             okButton.setOnHoverListener(mLiftToActivateListener);
114         }
115     }
116 
117     @Override
onViewDetached()118     protected void onViewDetached() {
119         super.onViewDetached();
120 
121         for (NumPadKey button: mView.getButtons()) {
122             button.setOnTouchListener(null);
123         }
124     }
125 
126     @Override
onResume(int reason)127     public void onResume(int reason) {
128         super.onResume(reason);
129         mPasswordEntry.requestFocus();
130     }
131 
132     @Override
resetState()133     void resetState() {
134         mView.setPasswordEntryEnabled(true);
135     }
136 }
137