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