1 /* 2 * Copyright (C) 2008 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.internal.policy.impl; 18 19 import android.app.Dialog; 20 import android.app.ProgressDialog; 21 import android.content.Context; 22 import android.content.res.Configuration; 23 import android.os.RemoteException; 24 import android.os.ServiceManager; 25 26 import com.android.internal.telephony.ITelephony; 27 import com.android.internal.widget.LockPatternUtils; 28 29 import android.text.Editable; 30 import android.util.Log; 31 import android.view.KeyEvent; 32 import android.view.LayoutInflater; 33 import android.view.View; 34 import android.view.WindowManager; 35 import android.widget.Button; 36 import android.widget.LinearLayout; 37 import android.widget.TextView; 38 import com.android.internal.R; 39 40 /** 41 * Displays a dialer like interface to unlock the SIM PUK. 42 */ 43 public class SimPukUnlockScreen extends LinearLayout implements KeyguardScreen, 44 View.OnClickListener, View.OnFocusChangeListener { 45 46 private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; 47 48 private final KeyguardUpdateMonitor mUpdateMonitor; 49 private final KeyguardScreenCallback mCallback; 50 private KeyguardStatusViewManager mKeyguardStatusViewManager; 51 52 private TextView mHeaderText; 53 private TextView mPukText; 54 private TextView mPinText; 55 private TextView mFocusedEntry; 56 57 private View mOkButton; 58 private View mDelPukButton; 59 private View mDelPinButton; 60 61 private ProgressDialog mSimUnlockProgressDialog = null; 62 63 private LockPatternUtils mLockPatternUtils; 64 65 private int mCreationOrientation; 66 67 private int mKeyboardHidden; 68 69 private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; 70 SimPukUnlockScreen(Context context, Configuration configuration, KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback, LockPatternUtils lockpatternutils)71 public SimPukUnlockScreen(Context context, Configuration configuration, 72 KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback, 73 LockPatternUtils lockpatternutils) { 74 super(context); 75 mUpdateMonitor = updateMonitor; 76 mCallback = callback;; 77 78 mCreationOrientation = configuration.orientation; 79 mKeyboardHidden = configuration.hardKeyboardHidden; 80 mLockPatternUtils = lockpatternutils; 81 82 LayoutInflater inflater = LayoutInflater.from(context); 83 if (mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { 84 inflater.inflate( 85 R.layout.keyguard_screen_sim_puk_landscape, this, true); 86 } else { 87 inflater.inflate( 88 R.layout.keyguard_screen_sim_puk_portrait, this, true); 89 new TouchInput(); 90 } 91 92 mHeaderText = (TextView) findViewById(R.id.headerText); 93 94 mPukText = (TextView) findViewById(R.id.pukDisplay); 95 mPinText = (TextView) findViewById(R.id.pinDisplay); 96 mDelPukButton = findViewById(R.id.pukDel); 97 mDelPinButton = findViewById(R.id.pinDel); 98 mOkButton = findViewById(R.id.ok); 99 100 mDelPinButton.setOnClickListener(this); 101 mDelPukButton.setOnClickListener(this); 102 mOkButton.setOnClickListener(this); 103 104 mHeaderText.setText(R.string.keyguard_password_enter_puk_code); 105 // To make marquee work 106 mHeaderText.setSelected(true); 107 108 mKeyguardStatusViewManager = new KeyguardStatusViewManager(this, updateMonitor, 109 lockpatternutils, callback, true); 110 111 mPinText.setFocusableInTouchMode(true); 112 mPinText.setOnFocusChangeListener(this); 113 mPukText.setFocusableInTouchMode(true); 114 mPukText.setOnFocusChangeListener(this); 115 } 116 117 /** {@inheritDoc} */ needsInput()118 public boolean needsInput() { 119 return false; 120 } 121 122 /** {@inheritDoc} */ onPause()123 public void onPause() { 124 mKeyguardStatusViewManager.onPause(); 125 } 126 127 /** {@inheritDoc} */ onResume()128 public void onResume() { 129 // start fresh 130 mHeaderText.setText(R.string.keyguard_password_enter_puk_code); 131 mKeyguardStatusViewManager.onResume(); 132 } 133 134 /** {@inheritDoc} */ cleanUp()135 public void cleanUp() { 136 // dismiss the dialog. 137 if (mSimUnlockProgressDialog != null) { 138 mSimUnlockProgressDialog.dismiss(); 139 mSimUnlockProgressDialog = null; 140 } 141 mUpdateMonitor.removeCallback(this); 142 } 143 144 145 /** 146 * Since the IPC can block, we want to run the request in a separate thread 147 * with a callback. 148 */ 149 private abstract class CheckSimPuk extends Thread { 150 151 private final String mPin, mPuk; 152 CheckSimPuk(String puk, String pin)153 protected CheckSimPuk(String puk, String pin) { 154 mPuk = puk; 155 mPin = pin; 156 } 157 onSimLockChangedResponse(boolean success)158 abstract void onSimLockChangedResponse(boolean success); 159 160 @Override run()161 public void run() { 162 try { 163 final boolean result = ITelephony.Stub.asInterface(ServiceManager 164 .checkService("phone")).supplyPuk(mPuk, mPin); 165 166 post(new Runnable() { 167 public void run() { 168 onSimLockChangedResponse(result); 169 } 170 }); 171 } catch (RemoteException e) { 172 post(new Runnable() { 173 public void run() { 174 onSimLockChangedResponse(false); 175 } 176 }); 177 } 178 } 179 } 180 onClick(View v)181 public void onClick(View v) { 182 if (v == mDelPukButton) { 183 if (mFocusedEntry != mPukText) 184 mPukText.requestFocus(); 185 final Editable digits = mPukText.getEditableText(); 186 final int len = digits.length(); 187 if (len > 0) { 188 digits.delete(len-1, len); 189 } 190 } else if (v == mDelPinButton) { 191 if (mFocusedEntry != mPinText) 192 mPinText.requestFocus(); 193 final Editable digits = mPinText.getEditableText(); 194 final int len = digits.length(); 195 if (len > 0) { 196 digits.delete(len-1, len); 197 } 198 } else if (v == mOkButton) { 199 checkPuk(); 200 } 201 mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); 202 203 } 204 205 @Override onFocusChange(View v, boolean hasFocus)206 public void onFocusChange(View v, boolean hasFocus) { 207 if (hasFocus) 208 mFocusedEntry = (TextView)v; 209 } 210 getSimUnlockProgressDialog()211 private Dialog getSimUnlockProgressDialog() { 212 if (mSimUnlockProgressDialog == null) { 213 mSimUnlockProgressDialog = new ProgressDialog(mContext); 214 mSimUnlockProgressDialog.setMessage( 215 mContext.getString(R.string.lockscreen_sim_unlock_progress_dialog_message)); 216 mSimUnlockProgressDialog.setIndeterminate(true); 217 mSimUnlockProgressDialog.setCancelable(false); 218 mSimUnlockProgressDialog.getWindow().setType( 219 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 220 } 221 return mSimUnlockProgressDialog; 222 } 223 checkPuk()224 private void checkPuk() { 225 // make sure that the puk is at least 8 digits long. 226 if (mPukText.getText().length() < 8) { 227 // otherwise, display a message to the user, and don't submit. 228 mHeaderText.setText(R.string.invalidPuk); 229 mPukText.setText(""); 230 return; 231 } 232 233 if (mPinText.getText().length() < 4 234 || mPinText.getText().length() > 8) { 235 // otherwise, display a message to the user, and don't submit. 236 mHeaderText.setText(R.string.invalidPin); 237 mPinText.setText(""); 238 return; 239 } 240 241 getSimUnlockProgressDialog().show(); 242 243 new CheckSimPuk(mPukText.getText().toString(), 244 mPinText.getText().toString()) { 245 void onSimLockChangedResponse(final boolean success) { 246 mPinText.post(new Runnable() { 247 public void run() { 248 if (mSimUnlockProgressDialog != null) { 249 mSimUnlockProgressDialog.hide(); 250 } 251 if (success) { 252 // before closing the keyguard, report back that 253 // the sim is unlocked so it knows right away 254 mUpdateMonitor.reportSimUnlocked(); 255 mCallback.goToUnlockScreen(); 256 } else { 257 mHeaderText.setText(R.string.badPuk); 258 mPukText.setText(""); 259 mPinText.setText(""); 260 } 261 } 262 }); 263 } 264 }.start(); 265 } 266 267 onKeyDown(int keyCode, KeyEvent event)268 public boolean onKeyDown(int keyCode, KeyEvent event) { 269 if (keyCode == KeyEvent.KEYCODE_BACK) { 270 mCallback.goToLockScreen(); 271 return true; 272 } 273 final char match = event.getMatch(DIGITS); 274 if (match != 0) { 275 reportDigit(match - '0'); 276 return true; 277 } 278 if (keyCode == KeyEvent.KEYCODE_DEL) { 279 mFocusedEntry.onKeyDown(keyCode, event); 280 final Editable digits = mFocusedEntry.getEditableText(); 281 final int len = digits.length(); 282 if (len > 0) { 283 digits.delete(len-1, len); 284 } 285 mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); 286 return true; 287 } 288 289 if (keyCode == KeyEvent.KEYCODE_ENTER) { 290 checkPuk(); 291 return true; 292 } 293 294 return false; 295 } 296 reportDigit(int digit)297 private void reportDigit(int digit) { 298 mFocusedEntry.append(Integer.toString(digit)); 299 } 300 updateConfiguration()301 void updateConfiguration() { 302 Configuration newConfig = getResources().getConfiguration(); 303 if (newConfig.orientation != mCreationOrientation) { 304 mCallback.recreateMe(newConfig); 305 } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) { 306 mKeyboardHidden = newConfig.hardKeyboardHidden; 307 } 308 309 } 310 311 @Override onAttachedToWindow()312 protected void onAttachedToWindow() { 313 super.onAttachedToWindow(); 314 updateConfiguration(); 315 } 316 317 /** {@inheritDoc} */ 318 @Override onConfigurationChanged(Configuration newConfig)319 protected void onConfigurationChanged(Configuration newConfig) { 320 super.onConfigurationChanged(newConfig); 321 updateConfiguration(); 322 } 323 324 /** 325 * Helper class to handle input from touch dialer. Only relevant when 326 * the keyboard is shut. 327 */ 328 private class TouchInput implements View.OnClickListener { 329 private TextView mZero; 330 private TextView mOne; 331 private TextView mTwo; 332 private TextView mThree; 333 private TextView mFour; 334 private TextView mFive; 335 private TextView mSix; 336 private TextView mSeven; 337 private TextView mEight; 338 private TextView mNine; 339 private TextView mCancelButton; 340 TouchInput()341 private TouchInput() { 342 mZero = (TextView) findViewById(R.id.zero); 343 mOne = (TextView) findViewById(R.id.one); 344 mTwo = (TextView) findViewById(R.id.two); 345 mThree = (TextView) findViewById(R.id.three); 346 mFour = (TextView) findViewById(R.id.four); 347 mFive = (TextView) findViewById(R.id.five); 348 mSix = (TextView) findViewById(R.id.six); 349 mSeven = (TextView) findViewById(R.id.seven); 350 mEight = (TextView) findViewById(R.id.eight); 351 mNine = (TextView) findViewById(R.id.nine); 352 mCancelButton = (TextView) findViewById(R.id.cancel); 353 354 mZero.setText("0"); 355 mOne.setText("1"); 356 mTwo.setText("2"); 357 mThree.setText("3"); 358 mFour.setText("4"); 359 mFive.setText("5"); 360 mSix.setText("6"); 361 mSeven.setText("7"); 362 mEight.setText("8"); 363 mNine.setText("9"); 364 365 mZero.setOnClickListener(this); 366 mOne.setOnClickListener(this); 367 mTwo.setOnClickListener(this); 368 mThree.setOnClickListener(this); 369 mFour.setOnClickListener(this); 370 mFive.setOnClickListener(this); 371 mSix.setOnClickListener(this); 372 mSeven.setOnClickListener(this); 373 mEight.setOnClickListener(this); 374 mNine.setOnClickListener(this); 375 mCancelButton.setOnClickListener(this); 376 } 377 378 onClick(View v)379 public void onClick(View v) { 380 if (v == mCancelButton) { 381 // clear the PIN/PUK entry fields if the user cancels 382 mPinText.setText(""); 383 mPukText.setText(""); 384 mCallback.goToLockScreen(); 385 return; 386 } 387 388 final int digit = checkDigit(v); 389 if (digit >= 0) { 390 mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); 391 reportDigit(digit); 392 } 393 } 394 checkDigit(View v)395 private int checkDigit(View v) { 396 int digit = -1; 397 if (v == mZero) { 398 digit = 0; 399 } else if (v == mOne) { 400 digit = 1; 401 } else if (v == mTwo) { 402 digit = 2; 403 } else if (v == mThree) { 404 digit = 3; 405 } else if (v == mFour) { 406 digit = 4; 407 } else if (v == mFive) { 408 digit = 5; 409 } else if (v == mSix) { 410 digit = 6; 411 } else if (v == mSeven) { 412 digit = 7; 413 } else if (v == mEight) { 414 digit = 8; 415 } else if (v == mNine) { 416 digit = 9; 417 } 418 return digit; 419 } 420 } 421 422 } 423