blob: 31518a1e31f8c7b4020d231ec0a8a58e5bf8f1fa [file] [log] [blame]
Jim Millerdcb3d842012-08-23 19:18:12 -07001/*
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 */
Jim Millerdcb3d842012-08-23 19:18:12 -070016
Jim Miller5ecd8112013-01-09 18:50:26 -080017package com.android.keyguard;
18
Jim Miller5ecd8112013-01-09 18:50:26 -080019import android.content.Context;
Wink Savilleb896b9f2013-10-23 15:44:26 -070020import android.animation.AnimatorSet.Builder;
Jim Millerdcb3d842012-08-23 19:18:12 -070021import android.app.Activity;
Wink Savilleb896b9f2013-10-23 15:44:26 -070022import android.app.AlertDialog;
Jim Millerdcb3d842012-08-23 19:18:12 -070023import android.app.Dialog;
24import android.app.ProgressDialog;
Jim Millerdcb3d842012-08-23 19:18:12 -070025import android.os.RemoteException;
26import android.os.ServiceManager;
27import android.text.Editable;
Daniel Sandler23d7a6e2012-11-02 00:21:07 -040028import android.text.InputType;
Jim Miller9cf2c522012-10-04 22:02:29 -070029import android.text.TextWatcher;
Daniel Sandler23d7a6e2012-11-02 00:21:07 -040030import android.text.method.DigitsKeyListener;
Jim Millerdcb3d842012-08-23 19:18:12 -070031import android.util.AttributeSet;
Wink Savilleb896b9f2013-10-23 15:44:26 -070032import android.util.Log;
Jim Millerdcb3d842012-08-23 19:18:12 -070033import android.view.View;
34import android.view.WindowManager;
Jim Millerdcb3d842012-08-23 19:18:12 -070035import android.widget.TextView.OnEditorActionListener;
36
Wink Savilleb896b9f2013-10-23 15:44:26 -070037import com.android.internal.telephony.ITelephony;
38import com.android.internal.telephony.PhoneConstants;
39
40
Daniel Sandler23d7a6e2012-11-02 00:21:07 -040041/**
42 * Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
43 */
44public class KeyguardSimPukView extends KeyguardAbsKeyInputView
45 implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
Wink Savilleb896b9f2013-10-23 15:44:26 -070046 private static final String LOG_TAG = "KeyguardSimPukView";
47 private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
Jim Millerdcb3d842012-08-23 19:18:12 -070048
49 private ProgressDialog mSimUnlockProgressDialog = null;
Jim Miller4b09dd32012-09-04 14:27:25 -070050 private volatile boolean mCheckInProgress;
Jim Miller3efe1062012-09-28 16:59:31 -070051 private String mPukText;
Jim Miller3efe1062012-09-28 16:59:31 -070052 private String mPinText;
53 private StateMachine mStateMachine = new StateMachine();
Wink Savilleb896b9f2013-10-23 15:44:26 -070054 private AlertDialog mRemainingAttemptsDialog;
Jim Miller3efe1062012-09-28 16:59:31 -070055
56 private class StateMachine {
57 final int ENTER_PUK = 0;
58 final int ENTER_PIN = 1;
59 final int CONFIRM_PIN = 2;
60 final int DONE = 3;
61 private int state = ENTER_PUK;
62
63 public void next() {
64 int msg = 0;
65 if (state == ENTER_PUK) {
66 if (checkPuk()) {
67 state = ENTER_PIN;
68 msg = R.string.kg_puk_enter_pin_hint;
69 } else {
70 msg = R.string.kg_invalid_sim_puk_hint;
71 }
72 } else if (state == ENTER_PIN) {
73 if (checkPin()) {
74 state = CONFIRM_PIN;
75 msg = R.string.kg_enter_confirm_pin_hint;
76 } else {
77 msg = R.string.kg_invalid_sim_pin_hint;
78 }
79 } else if (state == CONFIRM_PIN) {
80 if (confirmPin()) {
81 state = DONE;
Jim Miller5ecd8112013-01-09 18:50:26 -080082 msg = R.string.keyguard_sim_unlock_progress_dialog_message;
Jim Miller3efe1062012-09-28 16:59:31 -070083 updateSim();
84 } else {
Daniel Sandler23d7a6e2012-11-02 00:21:07 -040085 state = ENTER_PIN; // try again?
Jim Miller3efe1062012-09-28 16:59:31 -070086 msg = R.string.kg_invalid_confirm_pin_hint;
87 }
88 }
Daniel Sandler23d7a6e2012-11-02 00:21:07 -040089 mPasswordEntry.setText(null);
Jim Miller3efe1062012-09-28 16:59:31 -070090 if (msg != 0) {
Adam Cohen0a4f9002012-10-12 19:57:16 -070091 mSecurityMessageDisplay.setMessage(msg, true);
Jim Miller3efe1062012-09-28 16:59:31 -070092 }
93 }
94
95 void reset() {
96 mPinText="";
97 mPukText="";
98 state = ENTER_PUK;
Adam Cohen6dbf8612012-10-14 17:26:31 -070099 mSecurityMessageDisplay.setMessage(R.string.kg_puk_enter_puk_hint, true);
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400100 mPasswordEntry.requestFocus();
Jim Miller3efe1062012-09-28 16:59:31 -0700101 }
102 }
103
Wink Savilleb896b9f2013-10-23 15:44:26 -0700104 private String getPukPasswordErrorMessage(int attemptsRemaining) {
105 String displayMessage;
106
107 if (attemptsRemaining == 0) {
108 displayMessage = getContext().getString(R.string.kg_password_wrong_puk_code_dead);
109 } else if (attemptsRemaining > 0) {
110 displayMessage = getContext().getResources()
111 .getQuantityString(R.plurals.kg_password_wrong_puk_code, attemptsRemaining,
112 attemptsRemaining);
113 } else {
114 displayMessage = getContext().getString(R.string.kg_password_puk_failed);
115 }
116 if (DEBUG) Log.d(LOG_TAG, "getPukPasswordErrorMessage:"
117 + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
118 return displayMessage;
119 }
120
Jim Millerdcb3d842012-08-23 19:18:12 -0700121 public KeyguardSimPukView(Context context) {
122 this(context, null);
123 }
124
125 public KeyguardSimPukView(Context context, AttributeSet attrs) {
126 super(context, attrs);
Jim Millerdcb3d842012-08-23 19:18:12 -0700127 }
128
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400129 public void resetState() {
130 mStateMachine.reset();
131 mPasswordEntry.setEnabled(true);
132 }
133
134 @Override
Jim Miller7d5e00a2013-10-11 22:45:57 -0700135 protected boolean shouldLockout(long deadline) {
136 // SIM PUK doesn't have a timed lockout
137 return false;
138 }
139
140 @Override
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400141 protected int getPasswordTextViewId() {
142 return R.id.pinEntry;
Jim Millerdcb3d842012-08-23 19:18:12 -0700143 }
144
145 @Override
146 protected void onFinishInflate() {
147 super.onFinishInflate();
Jim Miller0b728242012-10-28 19:42:30 -0700148
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400149 final View ok = findViewById(R.id.key_enter);
150 if (ok != null) {
151 ok.setOnClickListener(new View.OnClickListener() {
152 @Override
153 public void onClick(View v) {
154 doHapticKeyClick();
155 verifyPasswordAndUnlock();
156 }
157 });
158 }
159
160 // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
161 // not a separate view
162 View pinDelete = findViewById(R.id.delete_button);
163 if (pinDelete != null) {
164 pinDelete.setVisibility(View.VISIBLE);
165 pinDelete.setOnClickListener(new OnClickListener() {
166 public void onClick(View v) {
167 CharSequence str = mPasswordEntry.getText();
168 if (str.length() > 0) {
169 mPasswordEntry.setText(str.subSequence(0, str.length()-1));
170 }
171 doHapticKeyClick();
172 }
173 });
174 pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
175 public boolean onLongClick(View v) {
176 mPasswordEntry.setText("");
177 doHapticKeyClick();
178 return true;
179 }
180 });
181 }
182
183 mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
184 mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
185 | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
186
187 mPasswordEntry.requestFocus();
188
Jim Miller0b728242012-10-28 19:42:30 -0700189 mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
Jim Millerdcb3d842012-08-23 19:18:12 -0700190 }
191
Adam Cohen6fb841f2012-10-24 13:15:38 -0700192 @Override
193 public void showUsabilityHint() {
194 }
195
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400196 @Override
197 public void onPause() {
Jim Millerdcb3d842012-08-23 19:18:12 -0700198 // dismiss the dialog.
199 if (mSimUnlockProgressDialog != null) {
200 mSimUnlockProgressDialog.dismiss();
201 mSimUnlockProgressDialog = null;
202 }
203 }
204
205 /**
206 * Since the IPC can block, we want to run the request in a separate thread
207 * with a callback.
208 */
209 private abstract class CheckSimPuk extends Thread {
210
211 private final String mPin, mPuk;
212
213 protected CheckSimPuk(String puk, String pin) {
214 mPuk = puk;
215 mPin = pin;
216 }
217
Wink Savilleb896b9f2013-10-23 15:44:26 -0700218 abstract void onSimLockChangedResponse(final int result, final int attemptsRemaining);
Jim Millerdcb3d842012-08-23 19:18:12 -0700219
220 @Override
221 public void run() {
222 try {
Wink Savilleb896b9f2013-10-23 15:44:26 -0700223 final int[] result = ITelephony.Stub.asInterface(ServiceManager
224 .checkService("phone")).supplyPukReportResult(mPuk, mPin);
Jim Millerdcb3d842012-08-23 19:18:12 -0700225
226 post(new Runnable() {
227 public void run() {
Wink Savilleb896b9f2013-10-23 15:44:26 -0700228 onSimLockChangedResponse(result[0], result[1]);
Jim Millerdcb3d842012-08-23 19:18:12 -0700229 }
230 });
231 } catch (RemoteException e) {
232 post(new Runnable() {
233 public void run() {
Wink Savilleb896b9f2013-10-23 15:44:26 -0700234 onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
Jim Millerdcb3d842012-08-23 19:18:12 -0700235 }
236 });
237 }
238 }
239 }
240
Jim Millerdcb3d842012-08-23 19:18:12 -0700241 private Dialog getSimUnlockProgressDialog() {
242 if (mSimUnlockProgressDialog == null) {
243 mSimUnlockProgressDialog = new ProgressDialog(mContext);
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400244 mSimUnlockProgressDialog.setMessage(
245 mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
Jim Millerdcb3d842012-08-23 19:18:12 -0700246 mSimUnlockProgressDialog.setIndeterminate(true);
247 mSimUnlockProgressDialog.setCancelable(false);
248 if (!(mContext instanceof Activity)) {
249 mSimUnlockProgressDialog.getWindow().setType(
250 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
251 }
252 }
253 return mSimUnlockProgressDialog;
254 }
255
Wink Savilleb896b9f2013-10-23 15:44:26 -0700256 private Dialog getPukRemainingAttemptsDialog(int remaining) {
257 String msg = getPukPasswordErrorMessage(remaining);
258 if (mRemainingAttemptsDialog == null) {
259 AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
260 builder.setMessage(msg);
261 builder.setCancelable(false);
262 builder.setNeutralButton(R.string.ok, null);
263 mRemainingAttemptsDialog = builder.create();
264 mRemainingAttemptsDialog.getWindow().setType(
265 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
266 } else {
267 mRemainingAttemptsDialog.setMessage(msg);
268 }
269 return mRemainingAttemptsDialog;
270 }
271
Jim Miller3efe1062012-09-28 16:59:31 -0700272 private boolean checkPuk() {
Jim Millerdcb3d842012-08-23 19:18:12 -0700273 // make sure the puk is at least 8 digits long.
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400274 if (mPasswordEntry.getText().length() >= 8) {
275 mPukText = mPasswordEntry.getText().toString();
Jim Miller3efe1062012-09-28 16:59:31 -0700276 return true;
Jim Millerdcb3d842012-08-23 19:18:12 -0700277 }
Jim Miller3efe1062012-09-28 16:59:31 -0700278 return false;
279 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700280
Jim Miller3efe1062012-09-28 16:59:31 -0700281 private boolean checkPin() {
Jim Millerdcb3d842012-08-23 19:18:12 -0700282 // make sure the PIN is between 4 and 8 digits
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400283 int length = mPasswordEntry.getText().length();
Jim Miller3efe1062012-09-28 16:59:31 -0700284 if (length >= 4 && length <= 8) {
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400285 mPinText = mPasswordEntry.getText().toString();
Jim Miller3efe1062012-09-28 16:59:31 -0700286 return true;
Jim Millerdcb3d842012-08-23 19:18:12 -0700287 }
Jim Miller3efe1062012-09-28 16:59:31 -0700288 return false;
289 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700290
Jim Miller3efe1062012-09-28 16:59:31 -0700291 public boolean confirmPin() {
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400292 return mPinText.equals(mPasswordEntry.getText().toString());
Jim Miller3efe1062012-09-28 16:59:31 -0700293 }
294
295 private void updateSim() {
Jim Millerdcb3d842012-08-23 19:18:12 -0700296 getSimUnlockProgressDialog().show();
297
Jim Miller4b09dd32012-09-04 14:27:25 -0700298 if (!mCheckInProgress) {
299 mCheckInProgress = true;
Jim Miller3efe1062012-09-28 16:59:31 -0700300 new CheckSimPuk(mPukText, mPinText) {
Wink Savilleb896b9f2013-10-23 15:44:26 -0700301 void onSimLockChangedResponse(final int result, final int attemptsRemaining) {
Jim Miller3efe1062012-09-28 16:59:31 -0700302 post(new Runnable() {
Jim Miller4b09dd32012-09-04 14:27:25 -0700303 public void run() {
304 if (mSimUnlockProgressDialog != null) {
305 mSimUnlockProgressDialog.hide();
306 }
Wink Savilleb896b9f2013-10-23 15:44:26 -0700307 if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
308 KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked();
Jim Miller4b09dd32012-09-04 14:27:25 -0700309 mCallback.dismiss(true);
310 } else {
Wink Savilleb896b9f2013-10-23 15:44:26 -0700311 if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
312 if (attemptsRemaining <= 2) {
313 // this is getting critical - show dialog
314 getPukRemainingAttemptsDialog(attemptsRemaining).show();
315 } else {
316 // show message
317 mSecurityMessageDisplay.setMessage(
318 getPukPasswordErrorMessage(attemptsRemaining), true);
319 }
320 } else {
321 mSecurityMessageDisplay.setMessage(getContext().getString(
322 R.string.kg_password_puk_failed), true);
323 }
324 if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock "
325 + " UpdateSim.onSimCheckResponse: "
326 + " attemptsRemaining=" + attemptsRemaining);
Jim Miller3efe1062012-09-28 16:59:31 -0700327 mStateMachine.reset();
Jim Miller4b09dd32012-09-04 14:27:25 -0700328 }
329 mCheckInProgress = false;
Jim Millerdcb3d842012-08-23 19:18:12 -0700330 }
Jim Miller4b09dd32012-09-04 14:27:25 -0700331 });
332 }
333 }.start();
334 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700335 }
336
337 @Override
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400338 protected void verifyPasswordAndUnlock() {
339 mStateMachine.next();
Jim Miller9cf2c522012-10-04 22:02:29 -0700340 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700341}
Daniel Sandler23d7a6e2012-11-02 00:21:07 -0400342
343