KeyguardSimPinView.java revision 0a4f900463024908220d0c9bf4b291a6e1284846
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 */ 16 17package com.android.internal.policy.impl.keyguard; 18 19import android.app.Activity; 20import android.app.Dialog; 21import android.app.ProgressDialog; 22import android.content.Context; 23import android.graphics.Rect; 24import android.os.RemoteException; 25import android.os.ServiceManager; 26 27import com.android.internal.telephony.ITelephony; 28import com.android.internal.widget.LockPatternUtils; 29import com.android.internal.widget.PasswordEntryKeyboardHelper; 30import com.android.internal.widget.PasswordEntryKeyboardView; 31import com.android.internal.R; 32 33import android.text.Editable; 34import android.text.TextWatcher; 35import android.util.AttributeSet; 36import android.view.KeyEvent; 37import android.view.MotionEvent; 38import android.view.View; 39import android.view.WindowManager; 40import android.view.inputmethod.EditorInfo; 41import android.widget.EditText; 42import android.widget.LinearLayout; 43import android.widget.TextView; 44import android.widget.TextView.OnEditorActionListener; 45 46/** 47 * Displays a dialer like interface to unlock the SIM PIN. 48 */ 49public class KeyguardSimPinView extends LinearLayout 50 implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { 51 52 private EditText mPinEntry; 53 private ProgressDialog mSimUnlockProgressDialog = null; 54 private KeyguardSecurityCallback mCallback; 55 private PasswordEntryKeyboardView mKeyboardView; 56 private PasswordEntryKeyboardHelper mKeyboardHelper; 57 private LockPatternUtils mLockPatternUtils; 58 private SecurityMessageDisplay mSecurityMessageDisplay; 59 60 private volatile boolean mSimCheckInProgress; 61 62 public KeyguardSimPinView(Context context) { 63 this(context, null); 64 } 65 66 public KeyguardSimPinView(Context context, AttributeSet attrs) { 67 super(context, attrs); 68 mLockPatternUtils = new LockPatternUtils(getContext()); 69 } 70 71 public void setKeyguardCallback(KeyguardSecurityCallback callback) { 72 mCallback = callback; 73 } 74 75 @Override 76 protected void onFinishInflate() { 77 super.onFinishInflate(); 78 79 mPinEntry = (EditText) findViewById(R.id.sim_pin_entry); 80 mPinEntry.setOnEditorActionListener(this); 81 mPinEntry.addTextChangedListener(this); 82 83 mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard); 84 mKeyboardHelper = new PasswordEntryKeyboardHelper(mContext, mKeyboardView, this, false, 85 new int[] { 86 R.xml.kg_password_kbd_numeric, 87 com.android.internal.R.xml.password_kbd_qwerty, 88 com.android.internal.R.xml.password_kbd_qwerty_shifted, 89 com.android.internal.R.xml.password_kbd_symbols, 90 com.android.internal.R.xml.password_kbd_symbols_shift 91 }); 92 mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); 93 mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled()); 94 95 final View deleteButton = findViewById(R.id.delete_button); 96 if (deleteButton != null) { 97 deleteButton.setOnClickListener(new OnClickListener() { 98 public void onClick(View v) { 99 mKeyboardHelper.handleBackspace(); 100 } 101 }); 102 } 103 reset(); 104 } 105 106 @Override 107 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 108 return mPinEntry.requestFocus(direction, previouslyFocusedRect); 109 } 110 111 public void reset() { 112 // start fresh 113 if (mSecurityMessageDisplay != null) { 114 mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true); 115 } 116 117 // make sure that the number of entered digits is consistent when we 118 // erase the SIM unlock code, including orientation changes. 119 mPinEntry.setText(""); 120 mPinEntry.requestFocus(); 121 } 122 123 /** {@inheritDoc} */ 124 public void cleanUp() { 125 // dismiss the dialog. 126 if (mSimUnlockProgressDialog != null) { 127 mSimUnlockProgressDialog.dismiss(); 128 mSimUnlockProgressDialog = null; 129 } 130 } 131 132 /** 133 * Since the IPC can block, we want to run the request in a separate thread 134 * with a callback. 135 */ 136 private abstract class CheckSimPin extends Thread { 137 private final String mPin; 138 139 protected CheckSimPin(String pin) { 140 mPin = pin; 141 } 142 143 abstract void onSimCheckResponse(boolean success); 144 145 @Override 146 public void run() { 147 try { 148 final boolean result = ITelephony.Stub.asInterface(ServiceManager 149 .checkService("phone")).supplyPin(mPin); 150 post(new Runnable() { 151 public void run() { 152 onSimCheckResponse(result); 153 } 154 }); 155 } catch (RemoteException e) { 156 post(new Runnable() { 157 public void run() { 158 onSimCheckResponse(false); 159 } 160 }); 161 } 162 } 163 } 164 165 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 166 // Check if this was the result of hitting the enter key 167 mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS); 168 if (event.getAction() == MotionEvent.ACTION_DOWN && ( 169 actionId == EditorInfo.IME_NULL 170 || actionId == EditorInfo.IME_ACTION_DONE 171 || actionId == EditorInfo.IME_ACTION_NEXT)) { 172 checkPin(); 173 return true; 174 } 175 return false; 176 } 177 178 private Dialog getSimUnlockProgressDialog() { 179 if (mSimUnlockProgressDialog == null) { 180 mSimUnlockProgressDialog = new ProgressDialog(mContext); 181 mSimUnlockProgressDialog.setMessage( 182 mContext.getString(R.string.kg_sim_unlock_progress_dialog_message)); 183 mSimUnlockProgressDialog.setIndeterminate(true); 184 mSimUnlockProgressDialog.setCancelable(false); 185 if (!(mContext instanceof Activity)) { 186 mSimUnlockProgressDialog.getWindow().setType( 187 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 188 } 189 } 190 return mSimUnlockProgressDialog; 191 } 192 193 private void checkPin() { 194 if (mPinEntry.getText().length() < 4) { 195 // otherwise, display a message to the user, and don't submit. 196 mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint, true); 197 mPinEntry.setText(""); 198 mCallback.userActivity(0); 199 return; 200 } 201 202 getSimUnlockProgressDialog().show(); 203 204 if (!mSimCheckInProgress) { 205 mSimCheckInProgress = true; // there should be only one 206 new CheckSimPin(mPinEntry.getText().toString()) { 207 void onSimCheckResponse(final boolean success) { 208 post(new Runnable() { 209 public void run() { 210 if (mSimUnlockProgressDialog != null) { 211 mSimUnlockProgressDialog.hide(); 212 } 213 if (success) { 214 // before closing the keyguard, report back that the sim is unlocked 215 // so it knows right away. 216 KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked(); 217 mCallback.dismiss(true); 218 } else { 219 mSecurityMessageDisplay.setMessage 220 (R.string.kg_password_wrong_pin_code, true); 221 mPinEntry.setText(""); 222 } 223 mCallback.userActivity(0); 224 mSimCheckInProgress = false; 225 } 226 }); 227 } 228 }.start(); 229 } 230 } 231 232 public void setLockPatternUtils(LockPatternUtils utils) { 233 mLockPatternUtils = utils; 234 } 235 236 public boolean needsInput() { 237 return false; // This view provides its own keypad 238 } 239 240 public void onPause() { 241 242 } 243 244 public void onResume() { 245 reset(); 246 } 247 248 public KeyguardSecurityCallback getCallback() { 249 return mCallback; 250 } 251 252 @Override 253 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 254 if (mCallback != null) { 255 mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS); 256 } 257 } 258 259 @Override 260 public void onTextChanged(CharSequence s, int start, int before, int count) { 261 } 262 263 @Override 264 public void afterTextChanged(Editable s) { 265 } 266 267 @Override 268 public void setSecurityMessageDisplay(SecurityMessageDisplay display) { 269 mSecurityMessageDisplay = display; 270 reset(); 271 } 272} 273