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