KeyguardSimPukView.java revision 6fb841fa219eaae3e87f2fdc05e105d7a1813c42
1/* 2 * Copyright (C) 2012 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 */ 16package com.android.internal.policy.impl.keyguard; 17 18import android.app.Activity; 19import android.app.Dialog; 20import android.app.ProgressDialog; 21import android.content.Context; 22import android.graphics.Rect; 23import android.os.RemoteException; 24import android.os.ServiceManager; 25import android.text.Editable; 26import android.text.TextWatcher; 27import android.util.AttributeSet; 28import android.view.KeyEvent; 29import android.view.MotionEvent; 30import android.view.View; 31import android.view.WindowManager; 32import android.view.inputmethod.EditorInfo; 33import android.widget.LinearLayout; 34import android.widget.TextView; 35import android.widget.TextView.OnEditorActionListener; 36 37import com.android.internal.telephony.ITelephony; 38import com.android.internal.widget.LockPatternUtils; 39import com.android.internal.widget.PasswordEntryKeyboardHelper; 40import com.android.internal.widget.PasswordEntryKeyboardView; 41import com.android.internal.R; 42 43public class KeyguardSimPukView extends LinearLayout implements View.OnClickListener, 44 KeyguardSecurityView, OnEditorActionListener, TextWatcher { 45 46 private View mDeleteButton; 47 48 private ProgressDialog mSimUnlockProgressDialog = null; 49 private KeyguardSecurityCallback mCallback; 50 51 private SecurityMessageDisplay mSecurityMessageDisplay; 52 53 private PasswordEntryKeyboardView mKeyboardView; 54 55 private PasswordEntryKeyboardHelper mKeyboardHelper; 56 57 private LockPatternUtils mLockPatternUtils; 58 59 private volatile boolean mCheckInProgress; 60 61 private TextView mSimPinEntry; 62 63 private String mPukText; 64 65 private String mPinText; 66 private StateMachine mStateMachine = new StateMachine(); 67 68 private class StateMachine { 69 final int ENTER_PUK = 0; 70 final int ENTER_PIN = 1; 71 final int CONFIRM_PIN = 2; 72 final int DONE = 3; 73 private int state = ENTER_PUK; 74 75 public void next() { 76 int msg = 0; 77 if (state == ENTER_PUK) { 78 if (checkPuk()) { 79 state = ENTER_PIN; 80 msg = R.string.kg_puk_enter_pin_hint; 81 } else { 82 msg = R.string.kg_invalid_sim_puk_hint; 83 } 84 } else if (state == ENTER_PIN) { 85 if (checkPin()) { 86 state = CONFIRM_PIN; 87 msg = R.string.kg_enter_confirm_pin_hint; 88 } else { 89 msg = R.string.kg_invalid_sim_pin_hint; 90 } 91 } else if (state == CONFIRM_PIN) { 92 if (confirmPin()) { 93 state = DONE; 94 msg = 95 com.android.internal.R.string.lockscreen_sim_unlock_progress_dialog_message; 96 updateSim(); 97 } else { 98 msg = R.string.kg_invalid_confirm_pin_hint; 99 } 100 } 101 mSimPinEntry.setText(null); 102 if (msg != 0) { 103 mSecurityMessageDisplay.setMessage(msg, true); 104 } 105 } 106 107 void reset() { 108 mPinText=""; 109 mPukText=""; 110 state = ENTER_PUK; 111 mSecurityMessageDisplay.setMessage(R.string.kg_puk_enter_puk_hint, true); 112 mSimPinEntry.requestFocus(); 113 } 114 } 115 116 public KeyguardSimPukView(Context context) { 117 this(context, null); 118 } 119 120 public KeyguardSimPukView(Context context, AttributeSet attrs) { 121 super(context, attrs); 122 mLockPatternUtils = new LockPatternUtils(getContext()); 123 } 124 125 public void setKeyguardCallback(KeyguardSecurityCallback callback) { 126 mCallback = callback; 127 mLockPatternUtils = new LockPatternUtils(getContext()); 128 } 129 130 @Override 131 protected void onFinishInflate() { 132 super.onFinishInflate(); 133 134 // We always set a dummy NavigationManager to avoid null checks 135 mSecurityMessageDisplay = new KeyguardNavigationManager(null); 136 137 mSimPinEntry = (TextView) findViewById(R.id.sim_pin_entry); 138 mSimPinEntry.setOnEditorActionListener(this); 139 mSimPinEntry.addTextChangedListener(this); 140 mDeleteButton = findViewById(R.id.delete_button); 141 mDeleteButton.setOnClickListener(this); 142 mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard); 143 mKeyboardHelper = new PasswordEntryKeyboardHelper(mContext, mKeyboardView, this, false, 144 new int[] { 145 R.xml.kg_password_kbd_numeric, 146 com.android.internal.R.xml.password_kbd_qwerty, 147 com.android.internal.R.xml.password_kbd_qwerty_shifted, 148 com.android.internal.R.xml.password_kbd_symbols, 149 com.android.internal.R.xml.password_kbd_symbols_shift 150 }); 151 mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); 152 mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled()); 153 reset(); 154 } 155 156 @Override 157 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 158 return mSimPinEntry.requestFocus(direction, previouslyFocusedRect); 159 } 160 161 public boolean needsInput() { 162 return false; // This view provides its own keypad 163 } 164 165 public void onPause() { 166 167 } 168 169 public void onResume() { 170 reset(); 171 } 172 173 @Override 174 public void showUsabilityHint() { 175 } 176 177 /** {@inheritDoc} */ 178 public void cleanUp() { 179 // dismiss the dialog. 180 if (mSimUnlockProgressDialog != null) { 181 mSimUnlockProgressDialog.dismiss(); 182 mSimUnlockProgressDialog = null; 183 } 184 } 185 186 /** 187 * Since the IPC can block, we want to run the request in a separate thread 188 * with a callback. 189 */ 190 private abstract class CheckSimPuk extends Thread { 191 192 private final String mPin, mPuk; 193 194 protected CheckSimPuk(String puk, String pin) { 195 mPuk = puk; 196 mPin = pin; 197 } 198 199 abstract void onSimLockChangedResponse(boolean success); 200 201 @Override 202 public void run() { 203 try { 204 final boolean result = ITelephony.Stub.asInterface(ServiceManager 205 .checkService("phone")).supplyPuk(mPuk, mPin); 206 207 post(new Runnable() { 208 public void run() { 209 onSimLockChangedResponse(result); 210 } 211 }); 212 } catch (RemoteException e) { 213 post(new Runnable() { 214 public void run() { 215 onSimLockChangedResponse(false); 216 } 217 }); 218 } 219 } 220 } 221 222 public void onClick(View v) { 223 if (v == mDeleteButton) { 224 mSimPinEntry.requestFocus(); 225 final Editable digits = mSimPinEntry.getEditableText(); 226 final int len = digits.length(); 227 if (len > 0) { 228 digits.delete(len-1, len); 229 } 230 } 231 mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS); 232 } 233 234 private Dialog getSimUnlockProgressDialog() { 235 if (mSimUnlockProgressDialog == null) { 236 mSimUnlockProgressDialog = new ProgressDialog(mContext); 237 mSimUnlockProgressDialog.setMessage(mContext.getString( 238 R.string.kg_sim_unlock_progress_dialog_message)); 239 mSimUnlockProgressDialog.setIndeterminate(true); 240 mSimUnlockProgressDialog.setCancelable(false); 241 if (!(mContext instanceof Activity)) { 242 mSimUnlockProgressDialog.getWindow().setType( 243 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 244 } 245 } 246 return mSimUnlockProgressDialog; 247 } 248 249 private boolean checkPuk() { 250 // make sure the puk is at least 8 digits long. 251 if (mSimPinEntry.getText().length() >= 8) { 252 mPukText = mSimPinEntry.getText().toString(); 253 return true; 254 } 255 return false; 256 } 257 258 private boolean checkPin() { 259 // make sure the PIN is between 4 and 8 digits 260 int length = mSimPinEntry.getText().length(); 261 if (length >= 4 && length <= 8) { 262 mPinText = mSimPinEntry.getText().toString(); 263 return true; 264 } 265 return false; 266 } 267 268 public boolean confirmPin() { 269 return mPinText.equals(mSimPinEntry.getText().toString()); 270 } 271 272 private void updateSim() { 273 getSimUnlockProgressDialog().show(); 274 275 if (!mCheckInProgress) { 276 mCheckInProgress = true; 277 new CheckSimPuk(mPukText, mPinText) { 278 void onSimLockChangedResponse(final boolean success) { 279 post(new Runnable() { 280 public void run() { 281 if (mSimUnlockProgressDialog != null) { 282 mSimUnlockProgressDialog.hide(); 283 } 284 if (success) { 285 mCallback.dismiss(true); 286 } else { 287 mStateMachine.reset(); 288 mSecurityMessageDisplay.setMessage(R.string.kg_invalid_puk, true); 289 } 290 mCheckInProgress = false; 291 } 292 }); 293 } 294 }.start(); 295 } 296 } 297 298 @Override 299 public boolean onEditorAction(TextView view, int actionId, KeyEvent event) { 300 // Check if this was the result of hitting the enter key 301 mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS); 302 if (event.getAction() == MotionEvent.ACTION_DOWN) { 303 if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE 304 || actionId == EditorInfo.IME_ACTION_NEXT) { 305 mStateMachine.next(); 306 return true; 307 } 308 } 309 return false; 310 } 311 312 @Override 313 public void setLockPatternUtils(LockPatternUtils utils) { 314 mLockPatternUtils = utils; 315 } 316 317 @Override 318 public void reset() { 319 mStateMachine.reset(); 320 } 321 322 @Override 323 public KeyguardSecurityCallback getCallback() { 324 return mCallback; 325 } 326 327 @Override 328 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 329 if (mCallback != null) { 330 mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS); 331 } 332 } 333 334 @Override 335 public void onTextChanged(CharSequence s, int start, int before, int count) { 336 } 337 338 @Override 339 public void afterTextChanged(Editable s) { 340 } 341 342 @Override 343 public void setSecurityMessageDisplay(SecurityMessageDisplay display) { 344 mSecurityMessageDisplay = display; 345 reset(); 346 } 347} 348