| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.phone; |
| |
| import android.app.ActionBar; |
| import android.app.Dialog; |
| import android.content.Context; |
| import android.os.AsyncResult; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.os.PersistableBundle; |
| import android.preference.Preference; |
| import android.preference.PreferenceScreen; |
| import android.telephony.CarrierConfigManager; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| import android.util.Log; |
| import android.view.MenuItem; |
| import android.widget.Toast; |
| |
| import com.android.internal.telephony.CommandException; |
| import com.android.internal.telephony.CommandsInterface; |
| import com.android.internal.telephony.GsmCdmaPhone; |
| import com.android.internal.telephony.Phone; |
| import com.android.phone.settings.fdn.EditPinPreference; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * Implements the preference to enable/disable calling barring options and |
| * the dialogs to change the passward. |
| */ |
| public class GsmUmtsCallBarringOptions extends TimeConsumingPreferenceActivity |
| implements EditPinPreference.OnPinEnteredListener { |
| private static final String LOG_TAG = "GsmUmtsCallBarringOptions"; |
| private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2); |
| |
| // String keys for preference lookup |
| // Preference is handled solely in xml. |
| // Block all outgoing calls |
| private static final String BUTTON_BAOC_KEY = "button_baoc_key"; |
| // Block all outgoing international calls |
| private static final String BUTTON_BAOIC_KEY = "button_baoic_key"; |
| // Block all outgoing international roaming calls |
| private static final String BUTTON_BAOICxH_KEY = "button_baoicxh_key"; |
| // Block all incoming calls |
| private static final String BUTTON_BAIC_KEY = "button_baic_key"; |
| // Block all incoming international roaming calls |
| private static final String BUTTON_BAICr_KEY = "button_baicr_key"; |
| // Disable all barring |
| private static final String BUTTON_BA_ALL_KEY = "button_ba_all_key"; |
| // Change passward |
| private static final String BUTTON_BA_CHANGE_PW_KEY = "button_change_pw_key"; |
| |
| private static final String PW_CHANGE_STATE_KEY = "pin_change_state_key"; |
| private static final String OLD_PW_KEY = "old_pw_key"; |
| private static final String NEW_PW_KEY = "new_pw_key"; |
| private static final String DIALOG_MESSAGE_KEY = "dialog_message_key"; |
| private static final String DIALOG_PW_ENTRY_KEY = "dialog_pw_enter_key"; |
| private static final String KEY_STATUS = "toggle"; |
| private static final String PREFERENCE_ENABLED_KEY = "PREFERENCE_ENABLED"; |
| private static final String SAVED_BEFORE_LOAD_COMPLETED_KEY = "PROGRESS_SHOWING"; |
| |
| private CallBarringEditPreference mButtonBAOC; |
| private CallBarringEditPreference mButtonBAOIC; |
| private CallBarringEditPreference mButtonBAOICxH; |
| private CallBarringEditPreference mButtonBAIC; |
| private CallBarringEditPreference mButtonBAICr; |
| private CallBarringDeselectAllPreference mButtonDisableAll; |
| private EditPinPreference mButtonChangePW; |
| |
| // State variables |
| private int mPwChangeState; |
| private String mOldPassword; |
| private String mNewPassword; |
| private int mPwChangeDialogStrId; |
| |
| private static final int PW_CHANGE_OLD = 0; |
| private static final int PW_CHANGE_NEW = 1; |
| private static final int PW_CHANGE_REENTER = 2; |
| |
| private static final int BUSY_READING_DIALOG = 100; |
| private static final int BUSY_SAVING_DIALOG = 200; |
| |
| // Password change complete event |
| private static final int EVENT_PW_CHANGE_COMPLETE = 100; |
| // Disable all complete event |
| private static final int EVENT_DISABLE_ALL_COMPLETE = 200; |
| |
| private static final int PW_LENGTH = 4; |
| |
| private Phone mPhone; |
| private ArrayList<CallBarringEditPreference> mPreferences = |
| new ArrayList<CallBarringEditPreference>(); |
| private int mInitIndex = 0; |
| private boolean mFirstResume; |
| private Bundle mIcicle; |
| |
| private SubscriptionInfoHelper mSubscriptionInfoHelper; |
| private Dialog mProgressDialog; |
| |
| @Override |
| public void onPinEntered(EditPinPreference preference, boolean positiveResult) { |
| if (preference == mButtonChangePW) { |
| updatePWChangeState(positiveResult); |
| } else if (preference == mButtonDisableAll) { |
| disableAllBarring(positiveResult); |
| } |
| } |
| |
| /** |
| * Display a toast for message. |
| */ |
| private void displayMessage(int strId) { |
| Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show(); |
| } |
| |
| /** |
| * Attempt to disable all for call barring settings. |
| */ |
| private void disableAllBarring(boolean positiveResult) { |
| if (!positiveResult) { |
| // Return on cancel |
| return; |
| } |
| |
| String password = mButtonDisableAll.getText(); |
| // Validate the length of password first, before submitting it to the |
| // RIL for CB disable. |
| if (!validatePassword(password)) { |
| mButtonDisableAll.setText(""); |
| displayMessage(R.string.call_barring_right_pwd_number); |
| return; |
| } |
| |
| // Submit the disable all request |
| mButtonDisableAll.setText(""); |
| Message onComplete = mHandler.obtainMessage(EVENT_DISABLE_ALL_COMPLETE); |
| mPhone.setCallBarring(CommandsInterface.CB_FACILITY_BA_ALL, false, password, onComplete, 0); |
| this.onStarted(mButtonDisableAll, false); |
| } |
| |
| /** |
| * Attempt to change the password for call barring settings. |
| */ |
| private void updatePWChangeState(boolean positiveResult) { |
| if (!positiveResult) { |
| // Reset the state on cancel |
| resetPwChangeState(); |
| return; |
| } |
| |
| // Progress through the dialog states, generally in this order: |
| // 1. Enter old password |
| // 2. Enter new password |
| // 3. Re-Enter new password |
| // In general, if any invalid entries are made, the dialog re- |
| // appears with text to indicate what the issue is. |
| switch (mPwChangeState) { |
| case PW_CHANGE_OLD: |
| mOldPassword = mButtonChangePW.getText(); |
| mButtonChangePW.setText(""); |
| if (validatePassword(mOldPassword)) { |
| mPwChangeState = PW_CHANGE_NEW; |
| displayPwChangeDialog(); |
| } else { |
| displayPwChangeDialog(R.string.call_barring_right_pwd_number, true); |
| } |
| break; |
| case PW_CHANGE_NEW: |
| mNewPassword = mButtonChangePW.getText(); |
| mButtonChangePW.setText(""); |
| if (validatePassword(mNewPassword)) { |
| mPwChangeState = PW_CHANGE_REENTER; |
| displayPwChangeDialog(); |
| } else { |
| displayPwChangeDialog(R.string.call_barring_right_pwd_number, true); |
| } |
| break; |
| case PW_CHANGE_REENTER: |
| // If the re-entered password is not valid, display a message |
| // and reset the state. |
| if (!mNewPassword.equals(mButtonChangePW.getText())) { |
| mPwChangeState = PW_CHANGE_NEW; |
| mButtonChangePW.setText(""); |
| displayPwChangeDialog(R.string.call_barring_pwd_not_match, true); |
| } else { |
| // If the password is valid, then submit the change password request |
| mButtonChangePW.setText(""); |
| Message onComplete = mHandler.obtainMessage(EVENT_PW_CHANGE_COMPLETE); |
| ((GsmCdmaPhone) mPhone).changeCallBarringPassword( |
| CommandsInterface.CB_FACILITY_BA_ALL, |
| mOldPassword, mNewPassword, onComplete); |
| this.onStarted(mButtonChangePW, false); |
| } |
| break; |
| default: |
| if (DBG) { |
| Log.d(LOG_TAG, "updatePWChangeState: Unknown password change state: " |
| + mPwChangeState); |
| } |
| break; |
| } |
| } |
| |
| /** |
| * Handler for asynchronous replies from the framework layer. |
| */ |
| private Handler mHandler = new Handler() { |
| @Override |
| public void handleMessage(Message msg) { |
| AsyncResult ar = (AsyncResult) msg.obj; |
| switch (msg.what) { |
| // Handle the response message for password change from the framework layer. |
| case EVENT_PW_CHANGE_COMPLETE: { |
| onFinished(mButtonChangePW, false); |
| // Unsuccessful change, display a toast to user with failure reason. |
| if (ar.exception != null) { |
| if (DBG) { |
| Log.d(LOG_TAG, |
| "change password for call barring failed with exception: " |
| + ar.exception); |
| } |
| onException(mButtonChangePW, (CommandException) ar.exception); |
| mButtonChangePW.setEnabled(true); |
| } else if (ar.userObj instanceof Throwable) { |
| onError(mButtonChangePW, RESPONSE_ERROR); |
| } else { |
| // Successful change. |
| displayMessage(R.string.call_barring_change_pwd_success); |
| } |
| resetPwChangeState(); |
| break; |
| } |
| // When disabling all call barring, either fail and display a toast, |
| // or just update the UI. |
| case EVENT_DISABLE_ALL_COMPLETE: { |
| onFinished(mButtonDisableAll, false); |
| if (ar.exception != null) { |
| if (DBG) { |
| Log.d(LOG_TAG, "can not disable all call barring with exception: " |
| + ar.exception); |
| } |
| onException(mButtonDisableAll, (CommandException) ar.exception); |
| mButtonDisableAll.setEnabled(true); |
| } else if (ar.userObj instanceof Throwable) { |
| onError(mButtonDisableAll, RESPONSE_ERROR); |
| } else { |
| // Reset to normal behaviour on successful change. |
| displayMessage(R.string.call_barring_deactivate_success); |
| resetCallBarringPrefState(false); |
| } |
| break; |
| } |
| default: { |
| if (DBG) { |
| Log.d(LOG_TAG, "Unknown message id: " + msg.what); |
| } |
| break; |
| } |
| } |
| } |
| }; |
| |
| /** |
| * The next two functions are for updating the message field on the dialog. |
| */ |
| private void displayPwChangeDialog() { |
| displayPwChangeDialog(0, true); |
| } |
| |
| private void displayPwChangeDialog(int strId, boolean shouldDisplay) { |
| int msgId = 0; |
| switch (mPwChangeState) { |
| case PW_CHANGE_OLD: |
| msgId = R.string.call_barring_old_pwd; |
| break; |
| case PW_CHANGE_NEW: |
| msgId = R.string.call_barring_new_pwd; |
| break; |
| case PW_CHANGE_REENTER: |
| msgId = R.string.call_barring_confirm_pwd; |
| break; |
| default: |
| break; |
| } |
| |
| // Append the note/additional message, if needed. |
| if (strId != 0) { |
| mButtonChangePW.setDialogMessage(getText(msgId) + "\n" + getText(strId)); |
| } else { |
| mButtonChangePW.setDialogMessage(msgId); |
| } |
| |
| // Only display if requested. |
| if (shouldDisplay) { |
| mButtonChangePW.showPinDialog(); |
| } |
| mPwChangeDialogStrId = strId; |
| } |
| |
| /** |
| * Reset the state of the password change dialog. |
| */ |
| private void resetPwChangeState() { |
| mPwChangeState = PW_CHANGE_OLD; |
| displayPwChangeDialog(0, false); |
| mOldPassword = ""; |
| mNewPassword = ""; |
| } |
| |
| /** |
| * Reset the state of the all call barring setting to disable. |
| */ |
| private void resetCallBarringPrefState(boolean enable) { |
| for (CallBarringEditPreference pref : mPreferences) { |
| pref.mIsActivated = enable; |
| pref.updateSummaryText(); |
| } |
| } |
| |
| /** |
| * Validate the password entry. |
| * |
| * @param password This is the password to validate |
| */ |
| private boolean validatePassword(String password) { |
| return password != null && password.length() == PW_LENGTH; |
| } |
| |
| @Override |
| protected void onCreate(Bundle icicle) { |
| super.onCreate(icicle); |
| if (DBG) { |
| Log.d(LOG_TAG, "onCreate, reading callbarring_options.xml file"); |
| } |
| addPreferencesFromResource(R.xml.callbarring_options); |
| |
| mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, getIntent()); |
| mPhone = mSubscriptionInfoHelper.getPhone(); |
| if (DBG) { |
| Log.d(LOG_TAG, "onCreate, reading callbarring_options.xml file finished!"); |
| } |
| |
| CarrierConfigManager configManager = (CarrierConfigManager) |
| mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); |
| PersistableBundle carrierConfig; |
| if (mSubscriptionInfoHelper.hasSubId()) { |
| carrierConfig = configManager.getConfigForSubId(mSubscriptionInfoHelper.getSubId()); |
| } else { |
| carrierConfig = configManager.getConfig(); |
| } |
| boolean isPwChangeButtonVisible = true; |
| boolean isDisableAllButtonVisible = true; |
| if (carrierConfig != null) { |
| isPwChangeButtonVisible = carrierConfig.getBoolean( |
| CarrierConfigManager.KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL, true); |
| isDisableAllButtonVisible = carrierConfig.getBoolean( |
| CarrierConfigManager.KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL, true); |
| } else { |
| Log.w(LOG_TAG, "Couldn't access CarrierConfig bundle"); |
| } |
| |
| // Get UI object references |
| PreferenceScreen prefSet = getPreferenceScreen(); |
| mButtonBAOC = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAOC_KEY); |
| mButtonBAOIC = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAOIC_KEY); |
| mButtonBAOICxH = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAOICxH_KEY); |
| mButtonBAIC = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAIC_KEY); |
| mButtonBAICr = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAICr_KEY); |
| mButtonDisableAll = (CallBarringDeselectAllPreference) |
| prefSet.findPreference(BUTTON_BA_ALL_KEY); |
| mButtonChangePW = (EditPinPreference) prefSet.findPreference(BUTTON_BA_CHANGE_PW_KEY); |
| |
| // Some carriers do not use PW change and disable all buttons. Hide them if this is the |
| // case. |
| if (!isDisableAllButtonVisible) { |
| prefSet.removePreference(mButtonDisableAll); |
| } |
| if (!isPwChangeButtonVisible) { |
| prefSet.removePreference(mButtonChangePW); |
| } |
| |
| // Assign click listener and update state |
| mButtonBAOC.setOnPinEnteredListener(this); |
| mButtonBAOIC.setOnPinEnteredListener(this); |
| mButtonBAOICxH.setOnPinEnteredListener(this); |
| mButtonBAIC.setOnPinEnteredListener(this); |
| mButtonBAICr.setOnPinEnteredListener(this); |
| mButtonDisableAll.setOnPinEnteredListener(this); |
| mButtonChangePW.setOnPinEnteredListener(this); |
| |
| // Store CallBarringEditPreferencence objects in array list. |
| mPreferences.add(mButtonBAOC); |
| mPreferences.add(mButtonBAOIC); |
| mPreferences.add(mButtonBAOICxH); |
| mPreferences.add(mButtonBAIC); |
| mPreferences.add(mButtonBAICr); |
| |
| // Find out if the sim card is ready. |
| boolean isSimReady = TelephonyManager.from(this).getSimState( |
| SubscriptionManager.getSlotIndex(mPhone.getSubId())) |
| == TelephonyManager.SIM_STATE_READY; |
| |
| // Deactivate all option and Change password option are unavailable |
| // when sim card is not ready. |
| if (isSimReady) { |
| mButtonDisableAll.setEnabled(true); |
| mButtonChangePW.setEnabled(true); |
| } else { |
| mButtonDisableAll.setEnabled(false); |
| mButtonChangePW.setEnabled(false); |
| mButtonChangePW.setSummary(R.string.call_barring_change_pwd_description_disabled); |
| } |
| |
| // Wait to do the initialization until onResume so that the TimeConsumingPreferenceActivity |
| // dialog can display as it relies on onResume / onPause to maintain its foreground state. |
| mFirstResume = true; |
| mIcicle = icicle; |
| |
| ActionBar actionBar = getActionBar(); |
| if (actionBar != null) { |
| // android.R.id.home will be triggered in onOptionsItemSelected() |
| actionBar.setDisplayHomeAsUpEnabled(true); |
| } |
| |
| if (mIcicle != null && !mIcicle.getBoolean(SAVED_BEFORE_LOAD_COMPLETED_KEY)) { |
| if (DBG) { |
| Log.d(LOG_TAG, "restore stored states"); |
| } |
| mInitIndex = mPreferences.size(); |
| |
| for (CallBarringEditPreference pref : mPreferences) { |
| Bundle bundle = mIcicle.getParcelable(pref.getKey()); |
| if (bundle != null) { |
| pref.handleCallBarringResult(bundle.getBoolean(KEY_STATUS)); |
| pref.init(this, true, mPhone); |
| pref.setEnabled(bundle.getBoolean(PREFERENCE_ENABLED_KEY, pref.isEnabled())); |
| } |
| } |
| mPwChangeState = mIcicle.getInt(PW_CHANGE_STATE_KEY); |
| mOldPassword = mIcicle.getString(OLD_PW_KEY); |
| mNewPassword = mIcicle.getString(NEW_PW_KEY); |
| displayPwChangeDialog(mIcicle.getInt(DIALOG_MESSAGE_KEY, mPwChangeDialogStrId), false); |
| mButtonChangePW.setText(mIcicle.getString(DIALOG_PW_ENTRY_KEY)); |
| } |
| } |
| |
| @Override |
| public void onResume() { |
| super.onResume(); |
| |
| if (mFirstResume) { |
| if (mIcicle == null || mIcicle.getBoolean(SAVED_BEFORE_LOAD_COMPLETED_KEY)) { |
| if (DBG) { |
| Log.d(LOG_TAG, "onResume: start to init "); |
| } |
| resetPwChangeState(); |
| mPreferences.get(mInitIndex).init(this, false, mPhone); |
| |
| // Request removing BUSY_SAVING_DIALOG because reading is restarted. |
| // (If it doesn't exist, nothing happen.) |
| removeDialog(BUSY_SAVING_DIALOG); |
| } |
| mFirstResume = false; |
| mIcicle = null; |
| } |
| } |
| |
| @Override |
| protected void onSaveInstanceState(Bundle outState) { |
| super.onSaveInstanceState(outState); |
| |
| for (CallBarringEditPreference pref : mPreferences) { |
| Bundle bundle = new Bundle(); |
| bundle.putBoolean(KEY_STATUS, pref.mIsActivated); |
| bundle.putBoolean(PREFERENCE_ENABLED_KEY, pref.isEnabled()); |
| outState.putParcelable(pref.getKey(), bundle); |
| } |
| outState.putInt(PW_CHANGE_STATE_KEY, mPwChangeState); |
| outState.putString(OLD_PW_KEY, mOldPassword); |
| outState.putString(NEW_PW_KEY, mNewPassword); |
| outState.putInt(DIALOG_MESSAGE_KEY, mPwChangeDialogStrId); |
| outState.putString(DIALOG_PW_ENTRY_KEY, mButtonChangePW.getText()); |
| |
| outState.putBoolean(SAVED_BEFORE_LOAD_COMPLETED_KEY, |
| mProgressDialog != null && mProgressDialog.isShowing()); |
| } |
| |
| /** |
| * Finish initialization of this preference and start next. |
| * |
| * @param preference The preference. |
| * @param reading If true to dismiss the busy reading dialog, |
| * false to dismiss the busy saving dialog. |
| */ |
| public void onFinished(Preference preference, boolean reading) { |
| if (mInitIndex < mPreferences.size() - 1 && !isFinishing()) { |
| mInitIndex++; |
| mPreferences.get(mInitIndex).init(this, false, mPhone); |
| } |
| super.onFinished(preference, reading); |
| } |
| |
| @Override |
| public boolean onOptionsItemSelected(MenuItem item) { |
| final int itemId = item.getItemId(); |
| if (itemId == android.R.id.home) { |
| CallFeaturesSetting.goUpToTopLevelSetting(this, mSubscriptionInfoHelper); |
| return true; |
| } |
| return super.onOptionsItemSelected(item); |
| } |
| |
| @Override |
| protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { |
| super.onPrepareDialog(id, dialog, args); |
| if (id == BUSY_READING_DIALOG || id == BUSY_SAVING_DIALOG) { |
| // For onSaveInstanceState, treat the SAVING dialog as the same as the READING. As |
| // the result, if the activity is recreated while waiting for SAVING, it starts reading |
| // all the newest data. |
| mProgressDialog = dialog; |
| } |
| } |
| } |