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 android.content.Context; 20 import android.graphics.Rect; 21 import android.util.AttributeSet; 22 import android.view.KeyEvent; 23 import android.view.MotionEvent; 24 import android.view.View; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 28 /** 29 * A Pin based Keyguard input view 30 */ 31 public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView 32 implements View.OnKeyListener, View.OnTouchListener { 33 34 protected PasswordTextView mPasswordEntry; 35 private View mOkButton; 36 private View mDeleteButton; 37 private View mButton0; 38 private View mButton1; 39 private View mButton2; 40 private View mButton3; 41 private View mButton4; 42 private View mButton5; 43 private View mButton6; 44 private View mButton7; 45 private View mButton8; 46 private View mButton9; 47 48 public KeyguardPinBasedInputView(Context context) { 49 this(context, null); 50 } 51 52 public KeyguardPinBasedInputView(Context context, AttributeSet attrs) { 53 super(context, attrs); 54 } 55 56 @Override 57 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 58 // send focus to the password field 59 return mPasswordEntry.requestFocus(direction, previouslyFocusedRect); 60 } 61 62 @Override 63 protected void resetState() { 64 setPasswordEntryEnabled(true); 65 } 66 67 @Override 68 protected void setPasswordEntryEnabled(boolean enabled) { 69 mPasswordEntry.setEnabled(enabled); 70 mOkButton.setEnabled(enabled); 71 } 72 73 @Override 74 protected void setPasswordEntryInputEnabled(boolean enabled) { 75 mPasswordEntry.setEnabled(enabled); 76 mOkButton.setEnabled(enabled); 77 } 78 79 @Override 80 public boolean onKeyDown(int keyCode, KeyEvent event) { 81 if (KeyEvent.isConfirmKey(keyCode)) { 82 performClick(mOkButton); 83 return true; 84 } else if (keyCode == KeyEvent.KEYCODE_DEL) { 85 performClick(mDeleteButton); 86 return true; 87 } 88 if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) { 89 int number = keyCode - KeyEvent.KEYCODE_0; 90 performNumberClick(number); 91 return true; 92 } 93 if (keyCode >= KeyEvent.KEYCODE_NUMPAD_0 && keyCode <= KeyEvent.KEYCODE_NUMPAD_9) { 94 int number = keyCode - KeyEvent.KEYCODE_NUMPAD_0; 95 performNumberClick(number); 96 return true; 97 } 98 return super.onKeyDown(keyCode, event); 99 } 100 101 @Override 102 protected int getPromptReasonStringRes(int reason) { 103 switch (reason) { 104 case PROMPT_REASON_RESTART: 105 return R.string.kg_prompt_reason_restart_pin; 106 case PROMPT_REASON_TIMEOUT: 107 return R.string.kg_prompt_reason_timeout_pin; 108 case PROMPT_REASON_DEVICE_ADMIN: 109 return R.string.kg_prompt_reason_device_admin; 110 case PROMPT_REASON_USER_REQUEST: 111 return R.string.kg_prompt_reason_user_request; 112 case PROMPT_REASON_NONE: 113 return 0; 114 default: 115 return R.string.kg_prompt_reason_timeout_pin; 116 } 117 } 118 119 private void performClick(View view) { 120 view.performClick(); 121 } 122 123 private void performNumberClick(int number) { 124 switch (number) { 125 case 0: 126 performClick(mButton0); 127 break; 128 case 1: 129 performClick(mButton1); 130 break; 131 case 2: 132 performClick(mButton2); 133 break; 134 case 3: 135 performClick(mButton3); 136 break; 137 case 4: 138 performClick(mButton4); 139 break; 140 case 5: 141 performClick(mButton5); 142 break; 143 case 6: 144 performClick(mButton6); 145 break; 146 case 7: 147 performClick(mButton7); 148 break; 149 case 8: 150 performClick(mButton8); 151 break; 152 case 9: 153 performClick(mButton9); 154 break; 155 } 156 } 157 158 @Override 159 protected void resetPasswordText(boolean animate, boolean announce) { 160 mPasswordEntry.reset(animate, announce); 161 } 162 163 @Override 164 protected String getPasswordText() { 165 return mPasswordEntry.getText(); 166 } 167 168 @Override 169 protected void onFinishInflate() { 170 mPasswordEntry = findViewById(getPasswordTextViewId()); 171 mPasswordEntry.setOnKeyListener(this); 172 173 // Set selected property on so the view can send accessibility events. 174 mPasswordEntry.setSelected(true); 175 176 mPasswordEntry.setUserActivityListener(new PasswordTextView.UserActivityListener() { 177 @Override 178 public void onUserActivity() { 179 onUserInput(); 180 } 181 }); 182 183 mOkButton = findViewById(R.id.key_enter); 184 if (mOkButton != null) { 185 mOkButton.setOnTouchListener(this); 186 mOkButton.setOnClickListener(new View.OnClickListener() { 187 @Override 188 public void onClick(View v) { 189 if (mPasswordEntry.isEnabled()) { 190 verifyPasswordAndUnlock(); 191 } 192 } 193 }); 194 mOkButton.setOnHoverListener(new LiftToActivateListener(getContext())); 195 } 196 197 mDeleteButton = findViewById(R.id.delete_button); 198 mDeleteButton.setVisibility(View.VISIBLE); 199 mDeleteButton.setOnTouchListener(this); 200 mDeleteButton.setOnClickListener(new OnClickListener() { 201 @Override 202 public void onClick(View v) { 203 // check for time-based lockouts 204 if (mPasswordEntry.isEnabled()) { 205 mPasswordEntry.deleteLastChar(); 206 } 207 } 208 }); 209 mDeleteButton.setOnLongClickListener(new View.OnLongClickListener() { 210 @Override 211 public boolean onLongClick(View v) { 212 // check for time-based lockouts 213 if (mPasswordEntry.isEnabled()) { 214 resetPasswordText(true /* animate */, true /* announce */); 215 } 216 doHapticKeyClick(); 217 return true; 218 } 219 }); 220 221 mButton0 = findViewById(R.id.key0); 222 mButton1 = findViewById(R.id.key1); 223 mButton2 = findViewById(R.id.key2); 224 mButton3 = findViewById(R.id.key3); 225 mButton4 = findViewById(R.id.key4); 226 mButton5 = findViewById(R.id.key5); 227 mButton6 = findViewById(R.id.key6); 228 mButton7 = findViewById(R.id.key7); 229 mButton8 = findViewById(R.id.key8); 230 mButton9 = findViewById(R.id.key9); 231 232 mPasswordEntry.requestFocus(); 233 super.onFinishInflate(); 234 } 235 236 @Override 237 public void onResume(int reason) { 238 super.onResume(reason); 239 mPasswordEntry.requestFocus(); 240 } 241 242 @Override 243 public boolean onTouch(View v, MotionEvent event) { 244 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 245 doHapticKeyClick(); 246 } 247 return false; 248 } 249 250 @Override 251 public boolean onKey(View v, int keyCode, KeyEvent event) { 252 if (event.getAction() == KeyEvent.ACTION_DOWN) { 253 return onKeyDown(keyCode, event); 254 } 255 return false; 256 } 257 258 @Override 259 public CharSequence getTitle() { 260 return getContext().getString( 261 com.android.internal.R.string.keyguard_accessibility_pin_unlock); 262 } 263 } 264