2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings;
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.os.AsyncResult;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.preference.CheckBoxPreference;
26 import android.preference.Preference;
27 import android.preference.PreferenceActivity;
28 import android.preference.PreferenceScreen;
29 import android.widget.Toast;
31 import com.android.internal.telephony.Phone;
32 import com.android.internal.telephony.PhoneFactory;
35 * Implements the preference screen to enable/disable ICC lock and
36 * also the dialogs to change the ICC PIN. In the former case, enabling/disabling
37 * the ICC lock will prompt the user for the current PIN.
38 * In the Change PIN case, it prompts the user for old pin, new pin and new pin
39 * again before attempting to change it. Calls the SimCard interface to execute
43 public class IccLockSettings extends PreferenceActivity
44 implements EditPinPreference.OnPinEnteredListener {
46 private static final int OFF_MODE = 0;
47 // State when enabling/disabling ICC lock
48 private static final int ICC_LOCK_MODE = 1;
49 // State when entering the old pin
50 private static final int ICC_OLD_MODE = 2;
51 // State when entering the new pin - first time
52 private static final int ICC_NEW_MODE = 3;
53 // State when entering the new pin - second time
54 private static final int ICC_REENTER_MODE = 4;
57 private static final String PIN_DIALOG = "sim_pin";
58 private static final String PIN_TOGGLE = "sim_toggle";
60 private static final String DIALOG_STATE = "dialogState";
61 private static final String DIALOG_PIN = "dialogPin";
62 private static final String DIALOG_ERROR = "dialogError";
63 private static final String ENABLE_TO_STATE = "enableState";
65 // Save and restore inputted PIN code when configuration changed
66 // (ex. portrait<-->landscape) during change PIN code
67 private static final String OLD_PINCODE = "oldPinCode";
68 private static final String NEW_PINCODE = "newPinCode";
70 private static final int MIN_PIN_LENGTH = 4;
71 private static final int MAX_PIN_LENGTH = 8;
72 // Which dialog to show next when popped up
73 private int mDialogState = OFF_MODE;
76 private String mOldPin;
77 private String mNewPin;
78 private String mError;
79 // Are we trying to enable or disable ICC lock?
80 private boolean mToState;
84 private EditPinPreference mPinDialog;
85 private CheckBoxPreference mPinToggle;
87 private Resources mRes;
89 // For async handler to identify request type
90 private static final int ENABLE_ICC_PIN_COMPLETE = 100;
91 private static final int CHANGE_ICC_PIN_COMPLETE = 101;
93 // For replies from IccCard interface
94 private Handler mHandler = new Handler() {
95 public void handleMessage(Message msg) {
96 AsyncResult ar = (AsyncResult) msg.obj;
98 case ENABLE_ICC_PIN_COMPLETE:
99 iccLockChanged(ar.exception == null);
101 case CHANGE_ICC_PIN_COMPLETE:
102 iccPinChanged(ar.exception == null);
110 // For top-level settings screen to query
111 static boolean isIccLockEnabled() {
112 return PhoneFactory.getDefaultPhone().getIccCard().getIccLockEnabled();
115 static String getSummary(Context context) {
116 Resources res = context.getResources();
117 String summary = isIccLockEnabled()
118 ? res.getString(R.string.sim_lock_on)
119 : res.getString(R.string.sim_lock_off);
124 protected void onCreate(Bundle savedInstanceState) {
125 super.onCreate(savedInstanceState);
127 if (Utils.isMonkeyRunning()) {
132 addPreferencesFromResource(R.xml.sim_lock_settings);
134 mPinDialog = (EditPinPreference) findPreference(PIN_DIALOG);
135 mPinToggle = (CheckBoxPreference) findPreference(PIN_TOGGLE);
136 if (savedInstanceState != null && savedInstanceState.containsKey(DIALOG_STATE)) {
137 mDialogState = savedInstanceState.getInt(DIALOG_STATE);
138 mPin = savedInstanceState.getString(DIALOG_PIN);
139 mError = savedInstanceState.getString(DIALOG_ERROR);
140 mToState = savedInstanceState.getBoolean(ENABLE_TO_STATE);
142 // Restore inputted PIN code
143 switch (mDialogState) {
145 mOldPin = savedInstanceState.getString(OLD_PINCODE);
148 case ICC_REENTER_MODE:
149 mOldPin = savedInstanceState.getString(OLD_PINCODE);
150 mNewPin = savedInstanceState.getString(NEW_PINCODE);
160 mPinDialog.setOnPinEnteredListener(this);
162 // Don't need any changes to be remembered
163 getPreferenceScreen().setPersistent(false);
165 mPhone = PhoneFactory.getDefaultPhone();
166 mRes = getResources();
170 protected void onResume() {
173 mPinToggle.setChecked(mPhone.getIccCard().getIccLockEnabled());
175 if (mDialogState != OFF_MODE) {
178 // Prep for standard click on "Change PIN"
184 protected void onSaveInstanceState(Bundle out) {
185 // Need to store this state for slider open/close
186 // There is one case where the dialog is popped up by the preference
187 // framework. In that case, let the preference framework store the
188 // dialog state. In other cases, where this activity manually launches
189 // the dialog, store the state of the dialog.
190 if (mPinDialog.isDialogOpen()) {
191 out.putInt(DIALOG_STATE, mDialogState);
192 out.putString(DIALOG_PIN, mPinDialog.getEditText().getText().toString());
193 out.putString(DIALOG_ERROR, mError);
194 out.putBoolean(ENABLE_TO_STATE, mToState);
196 // Save inputted PIN code
197 switch (mDialogState) {
199 out.putString(OLD_PINCODE, mOldPin);
202 case ICC_REENTER_MODE:
203 out.putString(OLD_PINCODE, mOldPin);
204 out.putString(NEW_PINCODE, mNewPin);
213 super.onSaveInstanceState(out);
217 private void showPinDialog() {
218 if (mDialogState == OFF_MODE) {
223 mPinDialog.showPinDialog();
226 private void setDialogValues() {
227 mPinDialog.setText(mPin);
229 switch (mDialogState) {
231 message = mRes.getString(R.string.sim_enter_pin);
232 mPinDialog.setDialogTitle(mToState
233 ? mRes.getString(R.string.sim_enable_sim_lock)
234 : mRes.getString(R.string.sim_disable_sim_lock));
237 message = mRes.getString(R.string.sim_enter_old);
238 mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
241 message = mRes.getString(R.string.sim_enter_new);
242 mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
244 case ICC_REENTER_MODE:
245 message = mRes.getString(R.string.sim_reenter_new);
246 mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
249 if (mError != null) {
250 message = mError + "\n" + message;
253 mPinDialog.setDialogMessage(message);
256 public void onPinEntered(EditPinPreference preference, boolean positiveResult) {
257 if (!positiveResult) {
262 mPin = preference.getText();
263 if (!reasonablePin(mPin)) {
264 // inject error message and display dialog again
265 mError = mRes.getString(R.string.sim_bad_pin);
269 switch (mDialogState) {
271 tryChangeIccLockState();
275 mDialogState = ICC_NEW_MODE;
282 mDialogState = ICC_REENTER_MODE;
286 case ICC_REENTER_MODE:
287 if (!mPin.equals(mNewPin)) {
288 mError = mRes.getString(R.string.sim_pins_dont_match);
289 mDialogState = ICC_NEW_MODE;
300 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
301 if (preference == mPinToggle) {
302 // Get the new, preferred state
303 mToState = mPinToggle.isChecked();
304 // Flip it back and pop up pin dialog
305 mPinToggle.setChecked(!mToState);
306 mDialogState = ICC_LOCK_MODE;
308 } else if (preference == mPinDialog) {
309 mDialogState = ICC_OLD_MODE;
315 private void tryChangeIccLockState() {
316 // Try to change icc lock. If it succeeds, toggle the lock state and
317 // reset dialog state. Else inject error message and show dialog again.
318 Message callback = Message.obtain(mHandler, ENABLE_ICC_PIN_COMPLETE);
319 mPhone.getIccCard().setIccLockEnabled(mToState, mPin, callback);
323 private void iccLockChanged(boolean success) {
325 mPinToggle.setChecked(mToState);
327 Toast.makeText(this, mRes.getString(R.string.sim_lock_failed), Toast.LENGTH_SHORT)
333 private void iccPinChanged(boolean success) {
335 Toast.makeText(this, mRes.getString(R.string.sim_change_failed),
339 Toast.makeText(this, mRes.getString(R.string.sim_change_succeeded),
347 private void tryChangePin() {
348 Message callback = Message.obtain(mHandler, CHANGE_ICC_PIN_COMPLETE);
349 mPhone.getIccCard().changeIccLockPassword(mOldPin,
353 private boolean reasonablePin(String pin) {
354 if (pin == null || pin.length() < MIN_PIN_LENGTH || pin.length() > MAX_PIN_LENGTH) {
361 private void resetDialogState() {
363 mDialogState = ICC_OLD_MODE; // Default for when Change PIN is clicked
366 mDialogState = OFF_MODE;