KeyguardSimPinView.java revision 76a1623afc170a13923b68f3256057d8adeb7937
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.keyguard; 18 19import com.android.internal.telephony.ITelephony; 20import com.android.internal.telephony.PhoneConstants; 21 22import android.content.Context; 23import android.app.AlertDialog; 24import android.app.AlertDialog.Builder; 25import android.app.Dialog; 26import android.app.ProgressDialog; 27import android.os.RemoteException; 28import android.os.ServiceManager; 29import android.util.AttributeSet; 30import android.util.Log; 31import android.view.WindowManager; 32 33/** 34 * Displays a PIN pad for unlocking. 35 */ 36public class KeyguardSimPinView extends KeyguardPinBasedInputView { 37 private static final String LOG_TAG = "KeyguardSimPinView"; 38 private static final boolean DEBUG = KeyguardConstants.DEBUG; 39 public static final String TAG = "KeyguardSimPinView"; 40 41 private ProgressDialog mSimUnlockProgressDialog = null; 42 private CheckSimPin mCheckSimPinThread; 43 44 private AlertDialog mRemainingAttemptsDialog; 45 46 public KeyguardSimPinView(Context context) { 47 this(context, null); 48 } 49 50 public KeyguardSimPinView(Context context, AttributeSet attrs) { 51 super(context, attrs); 52 } 53 54 public void resetState() { 55 super.resetState(); 56 mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true); 57 } 58 59 private String getPinPasswordErrorMessage(int attemptsRemaining) { 60 String displayMessage; 61 62 if (attemptsRemaining == 0) { 63 displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked); 64 } else if (attemptsRemaining > 0) { 65 displayMessage = getContext().getResources() 66 .getQuantityString(R.plurals.kg_password_wrong_pin_code, attemptsRemaining, 67 attemptsRemaining); 68 } else { 69 displayMessage = getContext().getString(R.string.kg_password_pin_failed); 70 } 71 if (DEBUG) Log.d(LOG_TAG, "getPinPasswordErrorMessage:" 72 + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage); 73 return displayMessage; 74 } 75 76 @Override 77 protected boolean shouldLockout(long deadline) { 78 // SIM PIN doesn't have a timed lockout 79 return false; 80 } 81 82 @Override 83 protected int getPasswordTextViewId() { 84 return R.id.simPinEntry; 85 } 86 87 @Override 88 protected void onFinishInflate() { 89 super.onFinishInflate(); 90 91 mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default 92 if (mEcaView instanceof EmergencyCarrierArea) { 93 ((EmergencyCarrierArea) mEcaView).setCarrierTextVisible(true); 94 } 95 } 96 97 @Override 98 public void showUsabilityHint() { 99 } 100 101 @Override 102 public void onPause() { 103 // dismiss the dialog. 104 if (mSimUnlockProgressDialog != null) { 105 mSimUnlockProgressDialog.dismiss(); 106 mSimUnlockProgressDialog = null; 107 } 108 } 109 110 /** 111 * Since the IPC can block, we want to run the request in a separate thread 112 * with a callback. 113 */ 114 private abstract class CheckSimPin extends Thread { 115 private final String mPin; 116 117 protected CheckSimPin(String pin) { 118 mPin = pin; 119 } 120 121 abstract void onSimCheckResponse(final int result, final int attemptsRemaining); 122 123 @Override 124 public void run() { 125 try { 126 Log.v(TAG, "call supplyPinReportResult()"); 127 final int[] result = ITelephony.Stub.asInterface(ServiceManager 128 .checkService("phone")).supplyPinReportResult(mPin); 129 Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]); 130 post(new Runnable() { 131 public void run() { 132 onSimCheckResponse(result[0], result[1]); 133 } 134 }); 135 } catch (RemoteException e) { 136 Log.e(TAG, "RemoteException for supplyPinReportResult:", e); 137 post(new Runnable() { 138 public void run() { 139 onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); 140 } 141 }); 142 } 143 } 144 } 145 146 private Dialog getSimUnlockProgressDialog() { 147 if (mSimUnlockProgressDialog == null) { 148 mSimUnlockProgressDialog = new ProgressDialog(mContext); 149 mSimUnlockProgressDialog.setMessage( 150 mContext.getString(R.string.kg_sim_unlock_progress_dialog_message)); 151 mSimUnlockProgressDialog.setIndeterminate(true); 152 mSimUnlockProgressDialog.setCancelable(false); 153 mSimUnlockProgressDialog.getWindow().setType( 154 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 155 } 156 return mSimUnlockProgressDialog; 157 } 158 159 private Dialog getSimRemainingAttemptsDialog(int remaining) { 160 String msg = getPinPasswordErrorMessage(remaining); 161 if (mRemainingAttemptsDialog == null) { 162 Builder builder = new AlertDialog.Builder(mContext); 163 builder.setMessage(msg); 164 builder.setCancelable(false); 165 builder.setNeutralButton(R.string.ok, null); 166 mRemainingAttemptsDialog = builder.create(); 167 mRemainingAttemptsDialog.getWindow().setType( 168 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 169 } else { 170 mRemainingAttemptsDialog.setMessage(msg); 171 } 172 return mRemainingAttemptsDialog; 173 } 174 175 @Override 176 protected void verifyPasswordAndUnlock() { 177 String entry = mPasswordEntry.getText(); 178 179 if (entry.length() < 4) { 180 // otherwise, display a message to the user, and don't submit. 181 mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint, true); 182 resetPasswordText(true); 183 mCallback.userActivity(); 184 return; 185 } 186 187 getSimUnlockProgressDialog().show(); 188 189 if (mCheckSimPinThread == null) { 190 mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText()) { 191 void onSimCheckResponse(final int result, final int attemptsRemaining) { 192 post(new Runnable() { 193 public void run() { 194 if (mSimUnlockProgressDialog != null) { 195 mSimUnlockProgressDialog.hide(); 196 } 197 if (result == PhoneConstants.PIN_RESULT_SUCCESS) { 198 KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked(); 199 mCallback.dismiss(true); 200 } else { 201 if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) { 202 if (attemptsRemaining <= 2) { 203 // this is getting critical - show dialog 204 getSimRemainingAttemptsDialog(attemptsRemaining).show(); 205 } else { 206 // show message 207 mSecurityMessageDisplay.setMessage( 208 getPinPasswordErrorMessage(attemptsRemaining), true); 209 } 210 } else { 211 // "PIN operation failed!" - no idea what this was and no way to 212 // find out. :/ 213 mSecurityMessageDisplay.setMessage(getContext().getString( 214 R.string.kg_password_pin_failed), true); 215 } 216 if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock " 217 + " CheckSimPin.onSimCheckResponse: " + result 218 + " attemptsRemaining=" + attemptsRemaining); 219 resetPasswordText(true /* animate */); 220 } 221 mCallback.userActivity(); 222 mCheckSimPinThread = null; 223 } 224 }); 225 } 226 }; 227 mCheckSimPinThread.start(); 228 } 229 } 230 231 @Override 232 public void startAppearAnimation() { 233 // noop. 234 } 235 236 @Override 237 public boolean startDisappearAnimation(Runnable finishRunnable) { 238 return false; 239 } 240} 241 242