blob: 286e3d6f1d0a3dc4441e9e0fef6587a8bcf10a5a [file] [log] [blame]
The Android Open Source Projectde2d9f52008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2008 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.settings;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.os.AsyncResult;
22import android.os.Bundle;
23import android.os.Handler;
24import android.os.Message;
25import android.preference.Preference;
26import android.preference.PreferenceActivity;
27import android.preference.CheckBoxPreference;
28import android.preference.PreferenceScreen;
29import com.android.internal.telephony.Phone;
30import com.android.internal.telephony.PhoneFactory;
31import android.widget.Toast;
32
33/**
34 * Implements the preference screen to enable/disable SIM lock and
35 * also the dialogs to change the SIM PIN. In the former case, enabling/disabling
36 * the SIM lock will prompt the user for the current PIN.
37 * In the Change PIN case, it prompts the user for old pin, new pin and new pin
38 * again before attempting to change it. Calls the SimCard interface to execute
39 * these operations.
40 *
41 */
42public class SimLockSettings extends PreferenceActivity
43 implements EditPinPreference.OnPinEnteredListener {
44
45 private static final int OFF_MODE = 0;
46 // State when enabling/disabling SIM lock
47 private static final int SIM_LOCK_MODE = 1;
48 // State when entering the old pin
49 private static final int SIM_OLD_MODE = 2;
50 // State when entering the new pin - first time
51 private static final int SIM_NEW_MODE = 3;
52 // State when entering the new pin - second time
53 private static final int SIM_REENTER_MODE = 4;
54
55 // Keys in xml file
56 private static final String PIN_DIALOG = "sim_pin";
57 private static final String PIN_TOGGLE = "sim_toggle";
58 // Keys in icicle
59 private static final String DIALOG_STATE = "dialogState";
60 private static final String DIALOG_PIN = "dialogPin";
61 private static final String DIALOG_ERROR = "dialogError";
62 private static final String ENABLE_TO_STATE = "enableState";
63
64 private static final int MIN_PIN_LENGTH = 4;
65 private static final int MAX_PIN_LENGTH = 8;
66 // Which dialog to show next when popped up
67 private int mDialogState = OFF_MODE;
68
69 private String mPin;
70 private String mOldPin;
71 private String mNewPin;
72 private String mError;
73 // Are we trying to enable or disable SIM lock?
74 private boolean mToState;
75
76 private Phone mPhone;
77
78 private EditPinPreference mPinDialog;
79 private CheckBoxPreference mPinToggle;
80
81 private Resources mRes;
82
83 // For async handler to identify request type
84 private static final int ENABLE_SIM_PIN_COMPLETE = 100;
85 private static final int CHANGE_SIM_PIN_COMPLETE = 101;
86
87 // For replies from SimCard interface
88 private Handler mHandler = new Handler() {
89 public void handleMessage(Message msg) {
90 AsyncResult ar = (AsyncResult) msg.obj;
91 switch (msg.what) {
92 case ENABLE_SIM_PIN_COMPLETE:
93 simLockChanged(ar.exception == null);
94 break;
95 case CHANGE_SIM_PIN_COMPLETE:
96 simPinChanged(ar.exception == null);
97 break;
98 }
99
100 return;
101 }
102 };
103
104 // For top-level settings screen to query
105 static boolean isSimLockEnabled() {
106 return PhoneFactory.getDefaultPhone().getSimCard().getSimLockEnabled();
107 }
108
109 static String getSummary(Context context) {
110 Resources res = context.getResources();
111 String summary = isSimLockEnabled()
112 ? res.getString(R.string.sim_lock_on)
113 : res.getString(R.string.sim_lock_off);
114 return summary;
115 }
116
117 @Override
118 protected void onCreate(Bundle savedInstanceState) {
119 super.onCreate(savedInstanceState);
120
121 addPreferencesFromResource(R.xml.sim_lock_settings);
122
123 mPinDialog = (EditPinPreference) findPreference(PIN_DIALOG);
124 mPinToggle = (CheckBoxPreference) findPreference(PIN_TOGGLE);
125 if (savedInstanceState != null && savedInstanceState.containsKey(DIALOG_STATE)) {
126 mDialogState = savedInstanceState.getInt(DIALOG_STATE);
127 mPin = savedInstanceState.getString(DIALOG_PIN);
128 mError = savedInstanceState.getString(DIALOG_ERROR);
129 mToState = savedInstanceState.getBoolean(ENABLE_TO_STATE);
130 }
131
132 mPinDialog.setOnPinEnteredListener(this);
133
134 // Don't need any changes to be remembered
135 getPreferenceScreen().setPersistent(false);
136
137 mPhone = PhoneFactory.getDefaultPhone();
138 mRes = getResources();
139 }
140
141 @Override
142 protected void onResume() {
143 super.onResume();
144
145 mPinToggle.setChecked(mPhone.getSimCard().getSimLockEnabled());
146
147 if (mDialogState != OFF_MODE) {
148 showPinDialog();
149 } else {
150 // Prep for standard click on "Change PIN"
151 resetDialogState();
152 }
153 }
154
155 @Override
156 protected void onSaveInstanceState(Bundle out) {
157 // Need to store this state for slider open/close
158 // There is one case where the dialog is popped up by the preference
159 // framework. In that case, let the preference framework store the
160 // dialog state. In other cases, where this activity manually launches
161 // the dialog, store the state of the dialog.
162 if (mPinDialog.isDialogOpen()) {
163 out.putInt(DIALOG_STATE, mDialogState);
164 out.putString(DIALOG_PIN, mPinDialog.getEditText().getText().toString());
165 out.putString(DIALOG_ERROR, mError);
166 out.putBoolean(ENABLE_TO_STATE, mToState);
167 } else {
168 super.onSaveInstanceState(out);
169 }
170 }
171
172 private void showPinDialog() {
173 if (mDialogState == OFF_MODE) {
174 return;
175 }
176 setDialogValues();
177
178 mPinDialog.showPinDialog();
179 }
180
181 private void setDialogValues() {
182 mPinDialog.setText(mPin);
183 String message = "";
184 switch (mDialogState) {
185 case SIM_LOCK_MODE:
186 message = mRes.getString(R.string.sim_enter_pin);
187 mPinDialog.setDialogTitle(mToState
188 ? mRes.getString(R.string.sim_enable_sim_lock)
189 : mRes.getString(R.string.sim_disable_sim_lock));
190 break;
191 case SIM_OLD_MODE:
192 message = mRes.getString(R.string.sim_enter_old);
193 mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
194 break;
195 case SIM_NEW_MODE:
196 message = mRes.getString(R.string.sim_enter_new);
197 mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
198 break;
199 case SIM_REENTER_MODE:
200 message = mRes.getString(R.string.sim_reenter_new);
201 mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
202 break;
203 }
204 if (mError != null) {
205 message = mError + "\n" + message;
206 mError = null;
207 }
208 mPinDialog.setDialogMessage(message);
209 }
210
211 public void onPinEntered(EditPinPreference preference, boolean positiveResult) {
212 if (!positiveResult) {
213 resetDialogState();
214 return;
215 }
216
217 mPin = preference.getText();
218 if (!reasonablePin(mPin)) {
219 // inject error message and display dialog again
220 mError = mRes.getString(R.string.sim_bad_pin);
221 showPinDialog();
222 return;
223 }
224 switch (mDialogState) {
225 case SIM_LOCK_MODE:
226 tryChangeSimLockState();
227 break;
228 case SIM_OLD_MODE:
229 mOldPin = mPin;
230 mDialogState = SIM_NEW_MODE;
231 mError = null;
232 mPin = null;
233 showPinDialog();
234 break;
235 case SIM_NEW_MODE:
236 mNewPin = mPin;
237 mDialogState = SIM_REENTER_MODE;
238 mPin = null;
239 showPinDialog();
240 break;
241 case SIM_REENTER_MODE:
242 if (!mPin.equals(mNewPin)) {
243 mError = mRes.getString(R.string.sim_pins_dont_match);
244 mDialogState = SIM_NEW_MODE;
245 mPin = null;
246 showPinDialog();
247 } else {
248 mError = null;
249 tryChangePin();
250 }
251 break;
252 }
253 }
254
255 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
256 if (preference == mPinToggle) {
257 // Get the new, preferred state
258 mToState = mPinToggle.isChecked();
259 // Flip it back and pop up pin dialog
260 mPinToggle.setChecked(!mToState);
261 mDialogState = SIM_LOCK_MODE;
262 showPinDialog();
263 }
264 return true;
265 }
266
267 private void tryChangeSimLockState() {
268 // Try to change sim lock. If it succeeds, toggle the lock state and
269 // reset dialog state. Else inject error message and show dialog again.
270 Message callback = Message.obtain(mHandler, ENABLE_SIM_PIN_COMPLETE);
271 mPhone.getSimCard().setSimLockEnabled(mToState, mPin, callback);
272
273 }
274
275 private void simLockChanged(boolean success) {
276 if (success) {
277 mPinToggle.setChecked(mToState);
278 } else {
279 // TODO: I18N
280 Toast.makeText(this, mRes.getString(R.string.sim_lock_failed), Toast.LENGTH_SHORT)
281 .show();
282 }
283 resetDialogState();
284 }
285
286 private void simPinChanged(boolean success) {
287 if (!success) {
288 // TODO: I18N
289 Toast.makeText(this, mRes.getString(R.string.sim_change_failed),
290 Toast.LENGTH_SHORT)
291 .show();
292 } else {
293 Toast.makeText(this, mRes.getString(R.string.sim_change_succeeded),
294 Toast.LENGTH_SHORT)
295 .show();
296
297 }
298 resetDialogState();
299 }
300
301 private void tryChangePin() {
302 Message callback = Message.obtain(mHandler, CHANGE_SIM_PIN_COMPLETE);
303 mPhone.getSimCard().changeSimLockPassword(mOldPin,
304 mNewPin, callback);
305 }
306
307 private boolean reasonablePin(String pin) {
308 if (pin == null || pin.length() < MIN_PIN_LENGTH || pin.length() > MAX_PIN_LENGTH) {
309 return false;
310 } else {
311 return true;
312 }
313 }
314
315 private void resetDialogState() {
316 mError = null;
317 mDialogState = SIM_OLD_MODE; // Default for when Change PIN is clicked
318 mPin = "";
319 setDialogValues();
320 }
321}