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