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