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