• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
20 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
21 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
22 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
23 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
24 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
25 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED;
26 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
27 
28 import android.animation.Animator;
29 import android.animation.AnimatorSet;
30 import android.animation.ValueAnimator;
31 import android.content.Context;
32 import android.graphics.Rect;
33 import android.util.AttributeSet;
34 import android.view.KeyEvent;
35 import android.view.View;
36 
37 import com.android.internal.widget.LockscreenCredential;
38 import com.android.systemui.R;
39 import com.android.systemui.animation.Interpolators;
40 
41 import java.util.ArrayList;
42 import java.util.List;
43 
44 /**
45  * A Pin based Keyguard input view
46  */
47 public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView {
48 
49     protected PasswordTextView mPasswordEntry;
50     private NumPadButton mOkButton;
51     private NumPadButton mDeleteButton;
52     private NumPadKey[] mButtons = new NumPadKey[10];
53 
KeyguardPinBasedInputView(Context context)54     public KeyguardPinBasedInputView(Context context) {
55         this(context, null);
56     }
57 
KeyguardPinBasedInputView(Context context, AttributeSet attrs)58     public KeyguardPinBasedInputView(Context context, AttributeSet attrs) {
59         super(context, attrs);
60     }
61 
62     @Override
onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)63     protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
64         // send focus to the password field
65         return mPasswordEntry.requestFocus(direction, previouslyFocusedRect);
66     }
67 
68     @Override
resetState()69     protected void resetState() {
70     }
71 
72     @Override
setPasswordEntryEnabled(boolean enabled)73     protected void setPasswordEntryEnabled(boolean enabled) {
74         mPasswordEntry.setEnabled(enabled);
75         mOkButton.setEnabled(enabled);
76         if (enabled && !mPasswordEntry.hasFocus()) {
77             mPasswordEntry.requestFocus();
78         }
79     }
80 
81     @Override
setPasswordEntryInputEnabled(boolean enabled)82     protected void setPasswordEntryInputEnabled(boolean enabled) {
83         mPasswordEntry.setEnabled(enabled);
84         mOkButton.setEnabled(enabled);
85         if (enabled && !mPasswordEntry.hasFocus()) {
86             mPasswordEntry.requestFocus();
87         }
88     }
89 
90     @Override
onKeyDown(int keyCode, KeyEvent event)91     public boolean onKeyDown(int keyCode, KeyEvent event) {
92         if (KeyEvent.isConfirmKey(keyCode)) {
93             mOkButton.performClick();
94             return true;
95         } else if (keyCode == KeyEvent.KEYCODE_DEL) {
96             mDeleteButton.performClick();
97             return true;
98         }
99         if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
100             int number = keyCode - KeyEvent.KEYCODE_0;
101             performNumberClick(number);
102             return true;
103         }
104         if (keyCode >= KeyEvent.KEYCODE_NUMPAD_0 && keyCode <= KeyEvent.KEYCODE_NUMPAD_9) {
105             int number = keyCode - KeyEvent.KEYCODE_NUMPAD_0;
106             performNumberClick(number);
107             return true;
108         }
109         return super.onKeyDown(keyCode, event);
110     }
111 
112     @Override
getPromptReasonStringRes(int reason)113     protected int getPromptReasonStringRes(int reason) {
114         switch (reason) {
115             case PROMPT_REASON_RESTART:
116                 return R.string.kg_prompt_reason_restart_pin;
117             case PROMPT_REASON_TIMEOUT:
118                 return R.string.kg_prompt_reason_timeout_pin;
119             case PROMPT_REASON_DEVICE_ADMIN:
120                 return R.string.kg_prompt_reason_device_admin;
121             case PROMPT_REASON_USER_REQUEST:
122                 return R.string.kg_prompt_reason_user_request;
123             case PROMPT_REASON_PREPARE_FOR_UPDATE:
124                 return R.string.kg_prompt_reason_timeout_pin;
125             case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
126                 return R.string.kg_prompt_reason_timeout_pin;
127             case PROMPT_REASON_TRUSTAGENT_EXPIRED:
128                 return R.string.kg_prompt_reason_timeout_pin;
129             case PROMPT_REASON_NONE:
130                 return 0;
131             default:
132                 return R.string.kg_prompt_reason_timeout_pin;
133         }
134     }
135 
performNumberClick(int number)136     private void performNumberClick(int number) {
137         if (number >= 0 && number <= 9) {
138             mButtons[number].performClick();
139         }
140     }
141 
142     @Override
resetPasswordText(boolean animate, boolean announce)143     protected void resetPasswordText(boolean animate, boolean announce) {
144         mPasswordEntry.reset(animate, announce);
145     }
146 
147     @Override
getEnteredCredential()148     protected LockscreenCredential getEnteredCredential() {
149         return LockscreenCredential.createPinOrNone(mPasswordEntry.getText());
150     }
151 
152     @Override
onFinishInflate()153     protected void onFinishInflate() {
154         mPasswordEntry = findViewById(getPasswordTextViewId());
155 
156         // Set selected property on so the view can send accessibility events.
157         mPasswordEntry.setSelected(true);
158 
159         mOkButton = findViewById(R.id.key_enter);
160 
161         mDeleteButton = findViewById(R.id.delete_button);
162         mDeleteButton.setVisibility(View.VISIBLE);
163 
164         mButtons[0] = findViewById(R.id.key0);
165         mButtons[1] = findViewById(R.id.key1);
166         mButtons[2] = findViewById(R.id.key2);
167         mButtons[3] = findViewById(R.id.key3);
168         mButtons[4] = findViewById(R.id.key4);
169         mButtons[5] = findViewById(R.id.key5);
170         mButtons[6] = findViewById(R.id.key6);
171         mButtons[7] = findViewById(R.id.key7);
172         mButtons[8] = findViewById(R.id.key8);
173         mButtons[9] = findViewById(R.id.key9);
174 
175         mPasswordEntry.requestFocus();
176         super.onFinishInflate();
177         reloadColors();
178     }
179 
getButtons()180     NumPadKey[] getButtons() {
181         return mButtons;
182     }
183 
184     /**
185      * Reload colors from resources.
186      **/
reloadColors()187     public void reloadColors() {
188         for (NumPadKey key : mButtons) {
189             key.reloadColors();
190         }
191         mPasswordEntry.reloadColors();
192         mDeleteButton.reloadColors();
193         mOkButton.reloadColors();
194     }
195 
196     @Override
getTitle()197     public CharSequence getTitle() {
198         return getContext().getString(
199                 com.android.internal.R.string.keyguard_accessibility_pin_unlock);
200     }
201 
202     /**
203      * Begins an error animation for this view.
204      **/
startErrorAnimation()205     public void startErrorAnimation() {
206         AnimatorSet animatorSet = new AnimatorSet();
207         List<Animator> animators = new ArrayList();
208         List<View> buttons = new ArrayList<>();
209         for (int i = 1; i <= 9; i++) {
210             buttons.add(mButtons[i]);
211         }
212         buttons.add(mDeleteButton);
213         buttons.add(mButtons[0]);
214         buttons.add(mOkButton);
215 
216         int delay = 0;
217         for (int i = 0; i < buttons.size(); i++) {
218             final View button = buttons.get(i);
219             AnimatorSet animateWrapper = new AnimatorSet();
220             animateWrapper.setStartDelay(delay);
221 
222             ValueAnimator scaleDownAnimator =  ValueAnimator.ofFloat(1f, 0.8f);
223             scaleDownAnimator.setInterpolator(Interpolators.STANDARD);
224             scaleDownAnimator.addUpdateListener(valueAnimator -> {
225                 button.setScaleX((float) valueAnimator.getAnimatedValue());
226                 button.setScaleY((float) valueAnimator.getAnimatedValue());
227             });
228             scaleDownAnimator.setDuration(50);
229 
230             ValueAnimator scaleUpAnimator =  ValueAnimator.ofFloat(0.8f, 1f);
231             scaleUpAnimator.setInterpolator(Interpolators.STANDARD);
232             scaleUpAnimator.addUpdateListener(valueAnimator -> {
233                 button.setScaleX((float) valueAnimator.getAnimatedValue());
234                 button.setScaleY((float) valueAnimator.getAnimatedValue());
235             });
236             scaleUpAnimator.setDuration(617);
237 
238             animateWrapper.playSequentially(scaleDownAnimator, scaleUpAnimator);
239             animators.add(animateWrapper);
240             delay += 33;
241         }
242         animatorSet.playTogether(animators);
243         animatorSet.start();
244     }
245 }
246