blob: 4b875ee1e4f6efbc58f0bdfad559dcf5d618f797 [file] [log] [blame]
Aida Takeshi7c3b4a32016-08-11 13:42:24 +08001/*
2 * Copyright (C) 2018 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.phone;
18
19import android.app.ActionBar;
20import android.app.Dialog;
21import android.os.AsyncResult;
22import android.os.Bundle;
23import android.os.Handler;
24import android.os.Message;
25import android.preference.Preference;
26import android.preference.PreferenceScreen;
27import android.telephony.ServiceState;
28import android.telephony.SubscriptionManager;
29import android.telephony.TelephonyManager;
30import android.util.Log;
31import android.view.MenuItem;
32import android.widget.Toast;
33
34import com.android.internal.telephony.CommandException;
35import com.android.internal.telephony.CommandsInterface;
36import com.android.internal.telephony.GsmCdmaPhone;
37import com.android.internal.telephony.Phone;
38import com.android.internal.telephony.imsphone.ImsPhone;
39import com.android.phone.settings.fdn.EditPinPreference;
40
41import java.util.ArrayList;
42
43/**
44 * Implements the preference to enable/disable calling barring options and
45 * the dialogs to change the passward.
46 */
47public class GsmUmtsCallBarringOptions extends TimeConsumingPreferenceActivity
48 implements EditPinPreference.OnPinEnteredListener {
49 private static final String LOG_TAG = "GsmUmtsCallBarringOptions";
50 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
51
52 // String keys for preference lookup
53 // Preference is handled solely in xml.
54 // Block all outgoing calls
55 private static final String BUTTON_BAOC_KEY = "button_baoc_key";
56 // Block all outgoing international calls
57 private static final String BUTTON_BAOIC_KEY = "button_baoic_key";
58 // Block all outgoing international roaming calls
59 private static final String BUTTON_BAOICxH_KEY = "button_baoicxh_key";
60 // Block all incoming calls
61 private static final String BUTTON_BAIC_KEY = "button_baic_key";
62 // Block all incoming international roaming calls
63 private static final String BUTTON_BAICr_KEY = "button_baicr_key";
64 // Disable all barring
65 private static final String BUTTON_BA_ALL_KEY = "button_ba_all_key";
66 // Change passward
67 private static final String BUTTON_BA_CHANGE_PW_KEY = "button_change_pw_key";
68
69 private static final String PW_CHANGE_STATE_KEY = "pin_change_state_key";
70 private static final String OLD_PW_KEY = "old_pw_key";
71 private static final String NEW_PW_KEY = "new_pw_key";
72 private static final String DIALOG_MESSAGE_KEY = "dialog_message_key";
73 private static final String DIALOG_PW_ENTRY_KEY = "dialog_pw_enter_key";
74 private static final String KEY_STATUS = "toggle";
75 private static final String PREFERENCE_ENABLED_KEY = "PREFERENCE_ENABLED";
76 private static final String PREFERENCE_SHOW_PASSWORD_KEY = "PREFERENCE_SHOW_PASSWORD";
77 private static final String SAVED_BEFORE_LOAD_COMPLETED_KEY = "PROGRESS_SHOWING";
78
79 private CallBarringEditPreference mButtonBAOC;
80 private CallBarringEditPreference mButtonBAOIC;
81 private CallBarringEditPreference mButtonBAOICxH;
82 private CallBarringEditPreference mButtonBAIC;
83 private CallBarringEditPreference mButtonBAICr;
84 private CallBarringDeselectAllPreference mButtonDisableAll;
85 private EditPinPreference mButtonChangePW;
86
87 // State variables
88 private int mPwChangeState;
89 private String mOldPassword;
90 private String mNewPassword;
91 private int mPwChangeDialogStrId;
92
93 private static final int PW_CHANGE_OLD = 0;
94 private static final int PW_CHANGE_NEW = 1;
95 private static final int PW_CHANGE_REENTER = 2;
96
97 private static final int BUSY_READING_DIALOG = 100;
98 private static final int BUSY_SAVING_DIALOG = 200;
99
100 // Password change complete event
101 private static final int EVENT_PW_CHANGE_COMPLETE = 100;
102 // Disable all complete event
103 private static final int EVENT_DISABLE_ALL_COMPLETE = 200;
104
105 private static final int PW_LENGTH = 4;
106
107 private Phone mPhone;
108 private ArrayList<CallBarringEditPreference> mPreferences =
109 new ArrayList<CallBarringEditPreference>();
110 private int mInitIndex = 0;
111 private boolean mFirstResume;
112 private Bundle mIcicle;
113
114 private SubscriptionInfoHelper mSubscriptionInfoHelper;
115 private Dialog mProgressDialog;
116
117 @Override
118 public void onPinEntered(EditPinPreference preference, boolean positiveResult) {
119 if (preference == mButtonChangePW) {
120 updatePWChangeState(positiveResult);
121 } else if (preference == mButtonDisableAll) {
122 disableAllBarring(positiveResult);
123 }
124 }
125
126 /**
127 * Display a toast for message.
128 */
129 private void displayMessage(int strId) {
130 Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show();
131 }
132
133 /**
134 * Attempt to disable all for call barring settings.
135 */
136 private void disableAllBarring(boolean positiveResult) {
137 if (!positiveResult) {
138 // Return on cancel
139 return;
140 }
141
142 String password = null;
143 if (mButtonDisableAll.isPasswordShown()) {
144 password = mButtonDisableAll.getText();
145 // Validate the length of password first, before submitting it to the
146 // RIL for CB disable.
147 if (!validatePassword(password)) {
148 mButtonDisableAll.setText("");
149 displayMessage(R.string.call_barring_right_pwd_number);
150 return;
151 }
152 }
153
154 // Submit the disable all request
155 mButtonDisableAll.setText("");
156 Message onComplete = mHandler.obtainMessage(EVENT_DISABLE_ALL_COMPLETE);
157 mPhone.setCallBarring(CommandsInterface.CB_FACILITY_BA_ALL, false, password, onComplete, 0);
158 this.onStarted(mButtonDisableAll, false);
159 }
160
161 /**
162 * Attempt to change the password for call barring settings.
163 */
164 private void updatePWChangeState(boolean positiveResult) {
165 if (!positiveResult) {
166 // Reset the state on cancel
167 resetPwChangeState();
168 return;
169 }
170
171 // Progress through the dialog states, generally in this order:
172 // 1. Enter old password
173 // 2. Enter new password
174 // 3. Re-Enter new password
175 // In general, if any invalid entries are made, the dialog re-
176 // appears with text to indicate what the issue is.
177 switch (mPwChangeState) {
178 case PW_CHANGE_OLD:
179 mOldPassword = mButtonChangePW.getText();
180 mButtonChangePW.setText("");
181 if (validatePassword(mOldPassword)) {
182 mPwChangeState = PW_CHANGE_NEW;
183 displayPwChangeDialog();
184 } else {
185 displayPwChangeDialog(R.string.call_barring_right_pwd_number, true);
186 }
187 break;
188 case PW_CHANGE_NEW:
189 mNewPassword = mButtonChangePW.getText();
190 mButtonChangePW.setText("");
191 if (validatePassword(mNewPassword)) {
192 mPwChangeState = PW_CHANGE_REENTER;
193 displayPwChangeDialog();
194 } else {
195 displayPwChangeDialog(R.string.call_barring_right_pwd_number, true);
196 }
197 break;
198 case PW_CHANGE_REENTER:
199 // If the re-entered password is not valid, display a message
200 // and reset the state.
201 if (!mNewPassword.equals(mButtonChangePW.getText())) {
202 mPwChangeState = PW_CHANGE_NEW;
203 mButtonChangePW.setText("");
204 displayPwChangeDialog(R.string.call_barring_pwd_not_match, true);
205 } else {
206 // If the password is valid, then submit the change password request
207 mButtonChangePW.setText("");
208 Message onComplete = mHandler.obtainMessage(EVENT_PW_CHANGE_COMPLETE);
209 ((GsmCdmaPhone) mPhone).changeCallBarringPassword(
210 CommandsInterface.CB_FACILITY_BA_ALL,
211 mOldPassword, mNewPassword, onComplete);
212 this.onStarted(mButtonChangePW, false);
213 }
214 break;
215 default:
216 if (DBG) {
217 Log.d(LOG_TAG, "updatePWChangeState: Unknown password change state: "
218 + mPwChangeState);
219 }
220 break;
221 }
222 }
223
224 /**
225 * Handler for asynchronous replies from the framework layer.
226 */
227 private Handler mHandler = new Handler() {
228 @Override
229 public void handleMessage(Message msg) {
230 AsyncResult ar = (AsyncResult) msg.obj;
231 switch (msg.what) {
232 // Handle the response message for password change from the framework layer.
233 case EVENT_PW_CHANGE_COMPLETE: {
234 onFinished(mButtonChangePW, false);
235 // Unsuccessful change, display a toast to user with failure reason.
236 if (ar.exception != null) {
237 if (DBG) {
238 Log.d(LOG_TAG,
239 "change password for call barring failed with exception: "
240 + ar.exception);
241 }
242 onException(mButtonChangePW, (CommandException) ar.exception);
243 mButtonChangePW.setEnabled(true);
244 } else if (ar.userObj instanceof Throwable) {
245 onError(mButtonChangePW, RESPONSE_ERROR);
246 } else {
247 // Successful change.
248 displayMessage(R.string.call_barring_change_pwd_success);
249 }
250 resetPwChangeState();
251 break;
252 }
253 // When disabling all call barring, either fail and display a toast,
254 // or just update the UI.
255 case EVENT_DISABLE_ALL_COMPLETE: {
256 onFinished(mButtonDisableAll, false);
257 if (ar.exception != null) {
258 if (DBG) {
259 Log.d(LOG_TAG, "can not disable all call barring with exception: "
260 + ar.exception);
261 }
262 onException(mButtonDisableAll, (CommandException) ar.exception);
263 mButtonDisableAll.setEnabled(true);
264 } else if (ar.userObj instanceof Throwable) {
265 onError(mButtonDisableAll, RESPONSE_ERROR);
266 } else {
267 // Reset to normal behaviour on successful change.
268 displayMessage(R.string.call_barring_deactivate_success);
269 resetCallBarringPrefState(false);
270 }
271 break;
272 }
273 default: {
274 if (DBG) {
275 Log.d(LOG_TAG, "Unknown message id: " + msg.what);
276 }
277 break;
278 }
279 }
280 }
281 };
282
283 /**
284 * The next two functions are for updating the message field on the dialog.
285 */
286 private void displayPwChangeDialog() {
287 displayPwChangeDialog(0, true);
288 }
289
290 private void displayPwChangeDialog(int strId, boolean shouldDisplay) {
291 int msgId = 0;
292 switch (mPwChangeState) {
293 case PW_CHANGE_OLD:
294 msgId = R.string.call_barring_old_pwd;
295 break;
296 case PW_CHANGE_NEW:
297 msgId = R.string.call_barring_new_pwd;
298 break;
299 case PW_CHANGE_REENTER:
300 msgId = R.string.call_barring_confirm_pwd;
301 break;
302 default:
303 break;
304 }
305
306 // Append the note/additional message, if needed.
307 if (strId != 0) {
308 mButtonChangePW.setDialogMessage(getText(msgId) + "\n" + getText(strId));
309 } else {
310 mButtonChangePW.setDialogMessage(msgId);
311 }
312
313 // Only display if requested.
314 if (shouldDisplay) {
315 mButtonChangePW.showPinDialog();
316 }
317 mPwChangeDialogStrId = strId;
318 }
319
320 /**
321 * Reset the state of the password change dialog.
322 */
323 private void resetPwChangeState() {
324 mPwChangeState = PW_CHANGE_OLD;
325 displayPwChangeDialog(0, false);
326 mOldPassword = "";
327 mNewPassword = "";
328 }
329
330 /**
331 * Reset the state of the all call barring setting to disable.
332 */
333 private void resetCallBarringPrefState(boolean enable) {
334 for (CallBarringEditPreference pref : mPreferences) {
335 pref.mIsActivated = enable;
336 pref.updateSummaryText();
337 }
338 }
339
340 /**
341 * Validate the password entry.
342 *
343 * @param password This is the password to validate
344 */
345 private boolean validatePassword(String password) {
346 return password != null && password.length() == PW_LENGTH;
347 }
348
349 @Override
350 protected void onCreate(Bundle icicle) {
351 super.onCreate(icicle);
352 if (DBG) {
353 Log.d(LOG_TAG, "onCreate, reading callbarring_options.xml file");
354 }
355 addPreferencesFromResource(R.xml.callbarring_options);
356
357 mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, getIntent());
358 mPhone = mSubscriptionInfoHelper.getPhone();
359 if (DBG) {
360 Log.d(LOG_TAG, "onCreate, reading callbarring_options.xml file finished!");
361 }
362
363 // Get UI object references
364 PreferenceScreen prefSet = getPreferenceScreen();
365 mButtonBAOC = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAOC_KEY);
366 mButtonBAOIC = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAOIC_KEY);
367 mButtonBAOICxH = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAOICxH_KEY);
368 mButtonBAIC = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAIC_KEY);
369 mButtonBAICr = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAICr_KEY);
370 mButtonDisableAll = (CallBarringDeselectAllPreference)
371 prefSet.findPreference(BUTTON_BA_ALL_KEY);
372 mButtonChangePW = (EditPinPreference) prefSet.findPreference(BUTTON_BA_CHANGE_PW_KEY);
373
374 // Assign click listener and update state
375 mButtonBAOC.setOnPinEnteredListener(this);
376 mButtonBAOIC.setOnPinEnteredListener(this);
377 mButtonBAOICxH.setOnPinEnteredListener(this);
378 mButtonBAIC.setOnPinEnteredListener(this);
379 mButtonBAICr.setOnPinEnteredListener(this);
380 mButtonDisableAll.setOnPinEnteredListener(this);
381 mButtonChangePW.setOnPinEnteredListener(this);
382
383 // Store CallBarringEditPreferencence objects in array list.
384 mPreferences.add(mButtonBAOC);
385 mPreferences.add(mButtonBAOIC);
386 mPreferences.add(mButtonBAOICxH);
387 mPreferences.add(mButtonBAIC);
388 mPreferences.add(mButtonBAICr);
389
390 // Find out if password is currently used.
391 boolean usePassword = true;
392 boolean useDisableaAll = true;
393
394 ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
395 if (imsPhone != null
396 && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
397 || imsPhone.isUtEnabled())) {
398 usePassword = false;
399 useDisableaAll = false;
400 }
401
402 // Find out if the sim card is ready.
403 boolean isSimReady = TelephonyManager.from(this).getSimState(
404 SubscriptionManager.getSlotIndex(mPhone.getSubId()))
405 == TelephonyManager.SIM_STATE_READY;
406
407 // Deactivate all option is unavailable when sim card is not ready or Ut is enabled.
408 if (isSimReady && useDisableaAll) {
409 mButtonDisableAll.setEnabled(true);
410 mButtonDisableAll.init(mPhone);
411 } else {
412 mButtonDisableAll.setEnabled(false);
413 }
414
415 // Change password option is unavailable when sim card is not ready or when the password is
416 // not used.
417 if (isSimReady && usePassword) {
418 mButtonChangePW.setEnabled(true);
419 } else {
420 mButtonChangePW.setEnabled(false);
421 mButtonChangePW.setSummary(R.string.call_barring_change_pwd_description_disabled);
422 }
423
424 // Wait to do the initialization until onResume so that the TimeConsumingPreferenceActivity
425 // dialog can display as it relies on onResume / onPause to maintain its foreground state.
426 mFirstResume = true;
427 mIcicle = icicle;
428
429 ActionBar actionBar = getActionBar();
430 if (actionBar != null) {
431 // android.R.id.home will be triggered in onOptionsItemSelected()
432 actionBar.setDisplayHomeAsUpEnabled(true);
433 }
434
435 if (mIcicle != null && !mIcicle.getBoolean(SAVED_BEFORE_LOAD_COMPLETED_KEY)) {
436 if (DBG) {
437 Log.d(LOG_TAG, "restore stored states");
438 }
439 mInitIndex = mPreferences.size();
440
441 for (CallBarringEditPreference pref : mPreferences) {
442 Bundle bundle = mIcicle.getParcelable(pref.getKey());
443 if (bundle != null) {
444 pref.handleCallBarringResult(bundle.getBoolean(KEY_STATUS));
445 pref.init(this, true, mPhone);
446 pref.setEnabled(bundle.getBoolean(PREFERENCE_ENABLED_KEY, pref.isEnabled()));
447 pref.setInputMethodNeeded(bundle.getBoolean(PREFERENCE_SHOW_PASSWORD_KEY,
448 pref.needInputMethod()));
449 }
450 }
451 mPwChangeState = mIcicle.getInt(PW_CHANGE_STATE_KEY);
452 mOldPassword = mIcicle.getString(OLD_PW_KEY);
453 mNewPassword = mIcicle.getString(NEW_PW_KEY);
454 displayPwChangeDialog(mIcicle.getInt(DIALOG_MESSAGE_KEY, mPwChangeDialogStrId), false);
455 mButtonChangePW.setText(mIcicle.getString(DIALOG_PW_ENTRY_KEY));
456 }
457 }
458
459 @Override
460 public void onResume() {
461 super.onResume();
462
463 if (mFirstResume) {
464 if (mIcicle == null || mIcicle.getBoolean(SAVED_BEFORE_LOAD_COMPLETED_KEY)) {
465 if (DBG) {
466 Log.d(LOG_TAG, "onResume: start to init ");
467 }
468 resetPwChangeState();
469 mPreferences.get(mInitIndex).init(this, false, mPhone);
470
471 // Request removing BUSY_SAVING_DIALOG because reading is restarted.
472 // (If it doesn't exist, nothing happen.)
473 removeDialog(BUSY_SAVING_DIALOG);
474 }
475 mFirstResume = false;
476 mIcicle = null;
477 }
478 }
479
480 @Override
481 protected void onSaveInstanceState(Bundle outState) {
482 super.onSaveInstanceState(outState);
483
484 for (CallBarringEditPreference pref : mPreferences) {
485 Bundle bundle = new Bundle();
486 bundle.putBoolean(KEY_STATUS, pref.mIsActivated);
487 bundle.putBoolean(PREFERENCE_ENABLED_KEY, pref.isEnabled());
488 bundle.putBoolean(PREFERENCE_SHOW_PASSWORD_KEY, pref.needInputMethod());
489 outState.putParcelable(pref.getKey(), bundle);
490 }
491 outState.putInt(PW_CHANGE_STATE_KEY, mPwChangeState);
492 outState.putString(OLD_PW_KEY, mOldPassword);
493 outState.putString(NEW_PW_KEY, mNewPassword);
494 outState.putInt(DIALOG_MESSAGE_KEY, mPwChangeDialogStrId);
495 outState.putString(DIALOG_PW_ENTRY_KEY, mButtonChangePW.getText());
496
497 outState.putBoolean(SAVED_BEFORE_LOAD_COMPLETED_KEY,
498 mProgressDialog != null && mProgressDialog.isShowing());
499 }
500
501 /**
502 * Finish initialization of this preference and start next.
503 *
504 * @param preference The preference.
505 * @param reading If true to dismiss the busy reading dialog,
506 * false to dismiss the busy saving dialog.
507 */
508 public void onFinished(Preference preference, boolean reading) {
509 if (mInitIndex < mPreferences.size() - 1 && !isFinishing()) {
510 mInitIndex++;
511 mPreferences.get(mInitIndex).init(this, false, mPhone);
512 }
513 super.onFinished(preference, reading);
514 }
515
516 @Override
517 public boolean onOptionsItemSelected(MenuItem item) {
518 final int itemId = item.getItemId();
519 if (itemId == android.R.id.home) {
520 CallFeaturesSetting.goUpToTopLevelSetting(this, mSubscriptionInfoHelper);
521 return true;
522 }
523 return super.onOptionsItemSelected(item);
524 }
525
526 @Override
527 protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
528 super.onPrepareDialog(id, dialog, args);
529 if (id == BUSY_READING_DIALOG || id == BUSY_SAVING_DIALOG) {
530 // For onSaveInstanceState, treat the SAVING dialog as the same as the READING. As
531 // the result, if the activity is recreated while waiting for SAVING, it starts reading
532 // all the newest data.
533 mProgressDialog = dialog;
534 }
535 }
536}