1 /* 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 17 package com.android.phone; 18 19 import android.app.AlertDialog; 20 import android.app.Dialog; 21 import android.app.ProgressDialog; 22 import android.content.Context; 23 import android.content.DialogInterface; 24 import android.content.Intent; 25 import android.content.SharedPreferences; 26 import android.content.SharedPreferences.Editor; 27 import android.content.pm.ActivityInfo; 28 import android.content.pm.PackageManager; 29 import android.content.pm.ResolveInfo; 30 import android.database.Cursor; 31 import android.media.AudioManager; 32 import android.net.sip.SipManager; 33 import android.net.sip.SipProfile; 34 import android.os.AsyncResult; 35 import android.os.Bundle; 36 import android.os.Handler; 37 import android.os.Message; 38 import android.preference.CheckBoxPreference; 39 import android.preference.ListPreference; 40 import android.preference.Preference; 41 import android.preference.PreferenceActivity; 42 import android.preference.PreferenceGroup; 43 import android.preference.PreferenceScreen; 44 import android.provider.Settings; 45 import android.provider.ContactsContract.CommonDataKinds; 46 import android.telephony.PhoneNumberUtils; 47 import android.text.TextUtils; 48 import android.util.Log; 49 import android.view.WindowManager; 50 import android.widget.ListAdapter; 51 52 import com.android.internal.telephony.CallForwardInfo; 53 import com.android.internal.telephony.CommandsInterface; 54 import com.android.internal.telephony.Phone; 55 import com.android.internal.telephony.PhoneFactory; 56 import com.android.internal.telephony.cdma.TtyIntent; 57 import com.android.phone.sip.SipSharedPreferences; 58 59 import java.util.Collection; 60 import java.util.HashMap; 61 import java.util.HashSet; 62 import java.util.Iterator; 63 import java.util.List; 64 import java.util.Map; 65 66 67 public class CallFeaturesSetting extends PreferenceActivity 68 implements DialogInterface.OnClickListener, 69 Preference.OnPreferenceChangeListener, 70 EditPhoneNumberPreference.OnDialogClosedListener, 71 EditPhoneNumberPreference.GetDefaultNumberListener{ 72 73 // intent action to bring up voice mail settings 74 public static final String ACTION_ADD_VOICEMAIL = 75 "com.android.phone.CallFeaturesSetting.ADD_VOICEMAIL"; 76 // intent action sent by this activity to a voice mail provider 77 // to trigger its configuration UI 78 public static final String ACTION_CONFIGURE_VOICEMAIL = 79 "com.android.phone.CallFeaturesSetting.CONFIGURE_VOICEMAIL"; 80 // Extra put in the return from VM provider config containing voicemail number to set 81 public static final String VM_NUMBER_EXTRA = "com.android.phone.VoicemailNumber"; 82 // Extra put in the return from VM provider config containing call forwarding number to set 83 public static final String FWD_NUMBER_EXTRA = "com.android.phone.ForwardingNumber"; 84 // Extra put in the return from VM provider config containing call forwarding number to set 85 public static final String FWD_NUMBER_TIME_EXTRA = "com.android.phone.ForwardingNumberTime"; 86 // If the VM provider returns non null value in this extra we will force the user to 87 // choose another VM provider 88 public static final String SIGNOUT_EXTRA = "com.android.phone.Signout"; 89 90 // Used to tell the saving logic to leave forwarding number as is 91 public static final CallForwardInfo[] FWD_SETTINGS_DONT_TOUCH = null; 92 // Suffix appended to provider key for storing vm number 93 public static final String VM_NUMBER_TAG = "#VMNumber"; 94 // Suffix appended to provider key for storing forwarding settings 95 public static final String FWD_SETTINGS_TAG = "#FWDSettings"; 96 // Suffix appended to forward settings key for storing length of settings array 97 public static final String FWD_SETTINGS_LENGTH_TAG = "#Length"; 98 // Suffix appended to forward settings key for storing an individual setting 99 public static final String FWD_SETTING_TAG = "#Setting"; 100 // Suffixes appended to forward setting key for storing an individual setting properties 101 public static final String FWD_SETTING_STATUS = "#Status"; 102 public static final String FWD_SETTING_REASON = "#Reason"; 103 public static final String FWD_SETTING_NUMBER = "#Number"; 104 public static final String FWD_SETTING_TIME = "#Time"; 105 106 // Key identifying the default vocie mail provider 107 public static final String DEFAULT_VM_PROVIDER_KEY = ""; 108 109 // Extra put into ACTION_ADD_VOICEMAIL call to indicate which provider 110 // to remove from the list of providers presented to the user 111 public static final String IGNORE_PROVIDER_EXTRA = "com.android.phone.ProviderToIgnore"; 112 113 // debug data 114 private static final String LOG_TAG = "CallFeaturesSetting"; 115 private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2); 116 117 // string constants 118 private static final String NUM_PROJECTION[] = {CommonDataKinds.Phone.NUMBER}; 119 120 // String keys for preference lookup 121 private static final String BUTTON_VOICEMAIL_KEY = "button_voicemail_key"; 122 private static final String BUTTON_VOICEMAIL_PROVIDER_KEY = "button_voicemail_provider_key"; 123 private static final String BUTTON_VOICEMAIL_SETTING_KEY = "button_voicemail_setting_key"; 124 private static final String BUTTON_FDN_KEY = "button_fdn_key"; 125 126 private static final String BUTTON_DTMF_KEY = "button_dtmf_settings"; 127 private static final String BUTTON_RETRY_KEY = "button_auto_retry_key"; 128 private static final String BUTTON_TTY_KEY = "button_tty_mode_key"; 129 private static final String BUTTON_HAC_KEY = "button_hac_key"; 130 131 private static final String BUTTON_GSM_UMTS_OPTIONS = "button_gsm_more_expand_key"; 132 private static final String BUTTON_CDMA_OPTIONS = "button_cdma_more_expand_key"; 133 134 private static final String VM_NUMBERS_SHARED_PREFERENCES_NAME = "vm_numbers"; 135 136 private static final String BUTTON_SIP_CALL_OPTIONS = 137 "sip_call_options_key"; 138 private static final String BUTTON_SIP_CALL_OPTIONS_WIFI_ONLY = 139 "sip_call_options_wifi_only_key"; 140 private static final String SIP_SETTINGS_CATEGORY_KEY = 141 "sip_settings_category_key"; 142 143 private Intent mContactListIntent; 144 145 /** Event for Async voicemail change call */ 146 private static final int EVENT_VOICEMAIL_CHANGED = 500; 147 private static final int EVENT_FORWARDING_CHANGED = 501; 148 private static final int EVENT_FORWARDING_GET_COMPLETED = 502; 149 150 // preferred TTY mode 151 // Phone.TTY_MODE_xxx 152 static final int preferredTtyMode = Phone.TTY_MODE_OFF; 153 154 // Dtmf tone types 155 static final int DTMF_TONE_TYPE_NORMAL = 0; 156 static final int DTMF_TONE_TYPE_LONG = 1; 157 158 public static final String HAC_KEY = "HACSetting"; 159 public static final String HAC_VAL_ON = "ON"; 160 public static final String HAC_VAL_OFF = "OFF"; 161 162 /** Handle to voicemail pref */ 163 private static final int VOICEMAIL_PREF_ID = 1; 164 private static final int VOICEMAIL_PROVIDER_CFG_ID = 2; 165 166 private Phone mPhone; 167 168 private AudioManager mAudioManager; 169 private SipManager mSipManager; 170 171 private static final int VM_NOCHANGE_ERROR = 400; 172 private static final int VM_RESPONSE_ERROR = 500; 173 private static final int FW_SET_RESPONSE_ERROR = 501; 174 private static final int FW_GET_RESPONSE_ERROR = 502; 175 176 177 // dialog identifiers for voicemail 178 private static final int VOICEMAIL_DIALOG_CONFIRM = 600; 179 private static final int VOICEMAIL_FWD_SAVING_DIALOG = 601; 180 private static final int VOICEMAIL_FWD_READING_DIALOG = 602; 181 private static final int VOICEMAIL_REVERTING_DIALOG = 603; 182 183 // status message sent back from handlers 184 private static final int MSG_OK = 100; 185 186 // special statuses for voicemail controls. 187 private static final int MSG_VM_EXCEPTION = 400; 188 private static final int MSG_FW_SET_EXCEPTION = 401; 189 private static final int MSG_FW_GET_EXCEPTION = 402; 190 private static final int MSG_VM_OK = 600; 191 private static final int MSG_VM_NOCHANGE = 700; 192 193 private EditPhoneNumberPreference mSubMenuVoicemailSettings; 194 195 private CheckBoxPreference mButtonAutoRetry; 196 private CheckBoxPreference mButtonHAC; 197 private ListPreference mButtonDTMF; 198 private ListPreference mButtonTTY; 199 private ListPreference mButtonSipCallOptions; 200 private ListPreference mVoicemailProviders; 201 private PreferenceScreen mVoicemailSettings; 202 private SipSharedPreferences mSipSharedPreferences; 203 204 private class VoiceMailProvider { 205 public VoiceMailProvider(String name, Intent intent) { 206 this.name = name; 207 this.intent = intent; 208 } 209 public String name; 210 public Intent intent; 211 } 212 213 /** 214 * Forwarding settings we are going to save. 215 */ 216 static final int [] FORWARDING_SETTINGS_REASONS = new int[] { 217 CommandsInterface.CF_REASON_UNCONDITIONAL, 218 CommandsInterface.CF_REASON_BUSY, 219 CommandsInterface.CF_REASON_NO_REPLY, 220 CommandsInterface.CF_REASON_NOT_REACHABLE 221 }; 222 223 private class VoiceMailProviderSettings { 224 /** 225 * Constructs settings object, setting all conditional forwarding to the specified number 226 */ 227 public VoiceMailProviderSettings(String voicemailNumber, String forwardingNumber, 228 int timeSeconds) { 229 this.voicemailNumber = voicemailNumber; 230 if (forwardingNumber == null || forwardingNumber.length() == 0) { 231 this.forwardingSettings = FWD_SETTINGS_DONT_TOUCH; 232 } else { 233 this.forwardingSettings = new CallForwardInfo[FORWARDING_SETTINGS_REASONS.length]; 234 for (int i = 0; i < this.forwardingSettings.length; i++) { 235 CallForwardInfo fi = new CallForwardInfo(); 236 this.forwardingSettings[i] = fi; 237 fi.reason = FORWARDING_SETTINGS_REASONS[i]; 238 fi.status = (fi.reason == CommandsInterface.CF_REASON_UNCONDITIONAL) ? 0 : 1; 239 fi.serviceClass = CommandsInterface.SERVICE_CLASS_VOICE; 240 fi.toa = PhoneNumberUtils.TOA_International; 241 fi.number = forwardingNumber; 242 fi.timeSeconds = timeSeconds; 243 } 244 } 245 } 246 247 public VoiceMailProviderSettings(String voicemailNumber, CallForwardInfo[] infos) { 248 this.voicemailNumber = voicemailNumber; 249 this.forwardingSettings = infos; 250 } 251 252 @Override 253 public boolean equals(Object o) { 254 if (o == null) return false; 255 if (!(o instanceof VoiceMailProviderSettings)) return false; 256 final VoiceMailProviderSettings v = (VoiceMailProviderSettings)o; 257 258 return ((this.voicemailNumber == null && 259 v.voicemailNumber == null) || 260 this.voicemailNumber != null && 261 this.voicemailNumber.equals(v.voicemailNumber)) 262 && 263 forwardingSettingsEqual(this.forwardingSettings, 264 v.forwardingSettings); 265 } 266 267 private boolean forwardingSettingsEqual(CallForwardInfo[] infos1, 268 CallForwardInfo[] infos2) { 269 if (infos1 == infos2) return true; 270 if (infos1 == null || infos2 == null) return false; 271 if (infos1.length != infos2.length) return false; 272 for (int i = 0; i < infos1.length; i++) { 273 CallForwardInfo i1 = infos1[i]; 274 CallForwardInfo i2 = infos2[i]; 275 if (i1.status != i2.status || 276 i1.reason != i2.reason || 277 i1.serviceClass != i2.serviceClass || 278 i1.toa != i2.toa || 279 i1.number != i2.number || 280 i1.timeSeconds != i2.timeSeconds) { 281 return false; 282 } 283 } 284 return true; 285 } 286 287 @Override 288 public String toString() { 289 return voicemailNumber + ((forwardingSettings != null ) ? (", " + 290 forwardingSettings.toString()) : ""); 291 } 292 293 public String voicemailNumber; 294 public CallForwardInfo[] forwardingSettings; 295 } 296 297 SharedPreferences mPerProviderSavedVMNumbers; 298 299 /** 300 * Results of reading forwarding settings 301 */ 302 CallForwardInfo[] mForwardingReadResults = null; 303 304 /** 305 * Result of forwarding number change. 306 * Keys are reasons (eg. unconditional forwarding). 307 */ 308 private Map<Integer, AsyncResult> mForwardingChangeResults = null; 309 310 /** 311 * Expected CF read result types. 312 * This set keeps track of the CF types for which we've issued change 313 * commands so we can tell when we've received all of the responses. 314 */ 315 private Collection<Integer> mExpectedChangeResultReasons = null; 316 317 /** 318 * Result of vm number change 319 */ 320 AsyncResult mVoicemailChangeResult = null; 321 322 /** 323 * Previous VM provider setting so we can return to it in case of failure. 324 */ 325 String mPreviousVMProviderKey = null; 326 327 /** 328 * Id of the dialog being currently shown. 329 */ 330 int mCurrentDialogId = 0; 331 332 /** 333 * Flag indicating that we are invoking settings for the voicemail provider programmatically 334 * due to vm provider change. 335 */ 336 boolean mVMProviderSettingsForced = false; 337 338 /** 339 * Flag indicating that we are making changes to vm or fwd numbers 340 * due to vm provider change. 341 */ 342 boolean mChangingVMorFwdDueToProviderChange = false; 343 344 /** 345 * True if we are in the process of vm & fwd number change and vm has already been changed. 346 * This is used to decide what to do in case of rollback. 347 */ 348 boolean mVMChangeCompletedSuccesfully = false; 349 350 /** 351 * True if we had full or partial failure setting forwarding numbers and so need to roll them 352 * back. 353 */ 354 boolean mFwdChangesRequireRollback = false; 355 356 /** 357 * Id of error msg to display to user once we are done reverting the VM provider to the previous 358 * one. 359 */ 360 int mVMOrFwdSetError = 0; 361 362 /** 363 * Data about discovered voice mail settings providers. 364 * Is populated by querying which activities can handle ACTION_CONFIGURE_VOICEMAIL. 365 * They key in this map is package name + activity name. 366 * We always add an entry for the default provider with a key of empty 367 * string and intent value of null. 368 * @see #initVoiceMailProviders. 369 */ 370 private final Map<String, VoiceMailProvider> mVMProvidersData = 371 new HashMap<String, VoiceMailProvider>(); 372 373 /** string to hold old voicemail number as it is being updated. */ 374 private String mOldVmNumber; 375 376 // New call forwarding settings and vm number we will be setting 377 // Need to save these since before we get to saving we need to asynchronously 378 // query the existing forwarding settings. 379 private CallForwardInfo[] mNewFwdSettings; 380 String mNewVMNumber; 381 382 private boolean mForeground; 383 384 @Override 385 public void onPause() { 386 super.onPause(); 387 mForeground = false; 388 } 389 390 /** 391 * We have to pull current settings from the network for all kinds of 392 * voicemail providers so we can tell whether we have to update them, 393 * so use this bit to keep track of whether we're reading settings for the 394 * default provider and should therefore save them out when done. 395 */ 396 private boolean mReadingSettingsForDefaultProvider = false; 397 398 /* 399 * Click Listeners, handle click based on objects attached to UI. 400 */ 401 402 // Click listener for all toggle events 403 @Override 404 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 405 if (preference == mSubMenuVoicemailSettings) { 406 return true; 407 } else if (preference == mButtonDTMF) { 408 return true; 409 } else if (preference == mButtonTTY) { 410 return true; 411 } else if (preference == mButtonAutoRetry) { 412 android.provider.Settings.System.putInt(mPhone.getContext().getContentResolver(), 413 android.provider.Settings.System.CALL_AUTO_RETRY, 414 mButtonAutoRetry.isChecked() ? 1 : 0); 415 return true; 416 } else if (preference == mButtonHAC) { 417 int hac = mButtonHAC.isChecked() ? 1 : 0; 418 // Update HAC value in Settings database 419 Settings.System.putInt(mPhone.getContext().getContentResolver(), 420 Settings.System.HEARING_AID, hac); 421 422 // Update HAC Value in AudioManager 423 mAudioManager.setParameter(HAC_KEY, hac != 0 ? HAC_VAL_ON : HAC_VAL_OFF); 424 return true; 425 } else if (preference == mVoicemailSettings && preference.getIntent() != null) { 426 if (DBG) log("Invoking cfg intent " + preference.getIntent().getPackage()); 427 this.startActivityForResult(preference.getIntent(), VOICEMAIL_PROVIDER_CFG_ID); 428 return true; 429 } 430 return false; 431 } 432 433 /** 434 * Implemented to support onPreferenceChangeListener to look for preference 435 * changes. 436 * 437 * @param preference is the preference to be changed 438 * @param objValue should be the value of the selection, NOT its localized 439 * display value. 440 */ 441 public boolean onPreferenceChange(Preference preference, Object objValue) { 442 if (preference == mButtonDTMF) { 443 int index = mButtonDTMF.findIndexOfValue((String) objValue); 444 Settings.System.putInt(mPhone.getContext().getContentResolver(), 445 Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, index); 446 } else if (preference == mButtonTTY) { 447 handleTTYChange(preference, objValue); 448 } else if (preference == mVoicemailProviders) { 449 final String currentProviderKey = getCurrentVoicemailProviderKey(); 450 final String newProviderKey = (String)objValue; 451 if (DBG) log("VM provider changes to " + newProviderKey + " from " + 452 mPreviousVMProviderKey); 453 if (mPreviousVMProviderKey.equals(newProviderKey)) { 454 if (DBG) log("No change "); 455 return true; 456 } 457 updateVMPreferenceWidgets(newProviderKey); 458 459 mPreviousVMProviderKey = currentProviderKey; 460 461 final VoiceMailProviderSettings newProviderSettings = 462 loadSettingsForVoiceMailProvider(newProviderKey); 463 464 // If the user switches to a voice mail provider and we have a 465 // numbers stored for it we will automatically change the 466 // phone's 467 // voice mail and forwarding number to the stored ones. 468 // Otherwise we will bring up provider's configuration UI. 469 470 if (newProviderSettings == null) { 471 // Force the user into a configuration of the chosen provider 472 if (DBG) log("Saved preferences not found - invoking config"); 473 mVMProviderSettingsForced = true; 474 simulatePreferenceClick(mVoicemailSettings); 475 } else { 476 if (DBG) log("Saved preferences found - switching to them"); 477 // Set this flag so if we get a failure we revert to previous provider 478 mChangingVMorFwdDueToProviderChange = true; 479 saveVoiceMailAndForwardingNumber(newProviderKey, newProviderSettings); 480 } 481 } else if (preference == mButtonSipCallOptions) { 482 handleSipCallOptionsChange(objValue); 483 } 484 // always let the preference setting proceed. 485 return true; 486 } 487 488 // Preference click listener invoked on OnDialogClosed for EditPhoneNumberPreference. 489 public void onDialogClosed(EditPhoneNumberPreference preference, int buttonClicked) { 490 if (DBG) log("onPreferenceClick: request preference click on dialog close: " + 491 buttonClicked); 492 if (buttonClicked == DialogInterface.BUTTON_NEGATIVE) { 493 return; 494 } 495 if (preference instanceof EditPhoneNumberPreference) { 496 EditPhoneNumberPreference epn = preference; 497 498 if (epn == mSubMenuVoicemailSettings) { 499 handleVMBtnClickRequest(); 500 } 501 } 502 } 503 504 /** 505 * Implemented for EditPhoneNumberPreference.GetDefaultNumberListener. 506 * This method set the default values for the various 507 * EditPhoneNumberPreference dialogs. 508 */ 509 public String onGetDefaultNumber(EditPhoneNumberPreference preference) { 510 if (preference == mSubMenuVoicemailSettings) { 511 // update the voicemail number field, which takes care of the 512 // mSubMenuVoicemailSettings itself, so we should return null. 513 if (DBG) log("updating default for voicemail dialog"); 514 updateVoiceNumberField(); 515 return null; 516 } 517 518 String vmDisplay = mPhone.getVoiceMailNumber(); 519 if (TextUtils.isEmpty(vmDisplay)) { 520 // if there is no voicemail number, we just return null to 521 // indicate no contribution. 522 return null; 523 } 524 525 // Return the voicemail number prepended with "VM: " 526 if (DBG) log("updating default for call forwarding dialogs"); 527 return getString(R.string.voicemail_abbreviated) + " " + vmDisplay; 528 } 529 530 531 // override the startsubactivity call to make changes in state consistent. 532 @Override 533 public void startActivityForResult(Intent intent, int requestCode) { 534 if (requestCode == -1) { 535 // this is an intent requested from the preference framework. 536 super.startActivityForResult(intent, requestCode); 537 return; 538 } 539 540 if (DBG) log("startSubActivity: starting requested subactivity"); 541 super.startActivityForResult(intent, requestCode); 542 } 543 544 private void switchToPreviousVoicemailProvider() { 545 if (DBG) log("switchToPreviousVoicemailProvider " + mPreviousVMProviderKey); 546 if (mPreviousVMProviderKey != null) { 547 if (mVMChangeCompletedSuccesfully || mFwdChangesRequireRollback) { 548 // we have to revert with carrier 549 showDialogIfForeground(VOICEMAIL_REVERTING_DIALOG); 550 VoiceMailProviderSettings prevSettings = 551 loadSettingsForVoiceMailProvider(mPreviousVMProviderKey); 552 if (mVMChangeCompletedSuccesfully) { 553 mNewVMNumber = prevSettings.voicemailNumber; 554 if (DBG) log("have to revert VM to " + mNewVMNumber); 555 mPhone.setVoiceMailNumber( 556 mPhone.getVoiceMailAlphaTag().toString(), 557 mNewVMNumber, 558 Message.obtain(mRevertOptionComplete, EVENT_VOICEMAIL_CHANGED)); 559 } 560 if (mFwdChangesRequireRollback) { 561 if (DBG) log("have to revert fwd"); 562 final CallForwardInfo[] prevFwdSettings = 563 prevSettings.forwardingSettings; 564 if (prevFwdSettings != null) { 565 Map<Integer, AsyncResult> results = 566 mForwardingChangeResults; 567 resetForwardingChangeState(); 568 for (int i = 0; i < prevFwdSettings.length; i++) { 569 CallForwardInfo fi = prevFwdSettings[i]; 570 if (DBG) log("Reverting fwd #: " + i + ": " + fi.toString()); 571 // Only revert the settings for which the update 572 // succeeded 573 AsyncResult result = results.get(fi.reason); 574 if (result != null && result.exception == null) { 575 mExpectedChangeResultReasons.add(fi.reason); 576 mPhone.setCallForwardingOption( 577 (fi.status == 1 ? 578 CommandsInterface.CF_ACTION_REGISTRATION : 579 CommandsInterface.CF_ACTION_DISABLE), 580 fi.reason, 581 fi.number, 582 fi.timeSeconds, 583 mRevertOptionComplete.obtainMessage( 584 EVENT_FORWARDING_CHANGED, i, 0)); 585 } 586 } 587 } 588 } 589 } else { 590 if (DBG) log("No need to revert"); 591 onRevertDone(); 592 } 593 } 594 } 595 596 void onRevertDone() { 597 if (DBG) log("Flipping provider key back to " + mPreviousVMProviderKey); 598 mVoicemailProviders.setValue(mPreviousVMProviderKey); 599 updateVMPreferenceWidgets(mPreviousVMProviderKey); 600 updateVoiceNumberField(); 601 if (mVMOrFwdSetError != 0) { 602 showVMDialog(mVMOrFwdSetError); 603 mVMOrFwdSetError = 0; 604 } 605 } 606 607 // asynchronous result call after contacts are selected or after we return from 608 // a call to the VM settings provider. 609 @Override 610 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 611 // there are cases where the contact picker may end up sending us more than one 612 // request. We want to ignore the request if we're not in the correct state. 613 if (requestCode == VOICEMAIL_PROVIDER_CFG_ID) { 614 boolean failure = false; 615 616 // No matter how the processing of result goes lets clear the flag 617 if (DBG) log("mVMProviderSettingsForced: " + mVMProviderSettingsForced); 618 final boolean isVMProviderSettingsForced = mVMProviderSettingsForced; 619 mVMProviderSettingsForced = false; 620 621 String vmNum = null; 622 if (resultCode != RESULT_OK) { 623 if (DBG) log("onActivityResult: vm provider cfg result not OK."); 624 failure = true; 625 } else { 626 if (data == null) { 627 if (DBG) log("onActivityResult: vm provider cfg result has no data"); 628 failure = true; 629 } else { 630 if (data.getBooleanExtra(SIGNOUT_EXTRA, false)) { 631 if (DBG) log("Provider requested signout"); 632 if (isVMProviderSettingsForced) { 633 if (DBG) log("Going back to previous provider on signout"); 634 switchToPreviousVoicemailProvider(); 635 } else { 636 final String victim = getCurrentVoicemailProviderKey(); 637 if (DBG) log("Relaunching activity and ignoring " + victim); 638 Intent i = new Intent(ACTION_ADD_VOICEMAIL); 639 i.putExtra(IGNORE_PROVIDER_EXTRA, victim); 640 i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 641 this.startActivity(i); 642 } 643 return; 644 } 645 vmNum = data.getStringExtra(VM_NUMBER_EXTRA); 646 if (vmNum == null || vmNum.length() == 0) { 647 if (DBG) log("onActivityResult: vm provider cfg result has no vmnum"); 648 failure = true; 649 } 650 } 651 } 652 if (failure) { 653 if (DBG) log("Failure in return from voicemail provider"); 654 if (isVMProviderSettingsForced) { 655 switchToPreviousVoicemailProvider(); 656 } else { 657 if (DBG) log("Not switching back the provider since this is not forced config"); 658 } 659 return; 660 } 661 mChangingVMorFwdDueToProviderChange = isVMProviderSettingsForced; 662 final String fwdNum = data.getStringExtra(FWD_NUMBER_EXTRA); 663 664 // TODO(iliat): It would be nice to load the current network setting for this and 665 // send it to the provider when it's config is invoked so it can use this as default 666 final int fwdNumTime = data.getIntExtra(FWD_NUMBER_TIME_EXTRA, 20); 667 668 if (DBG) log("onActivityResult: vm provider cfg result " + 669 (fwdNum != null ? "has" : " does not have") + " forwarding number"); 670 saveVoiceMailAndForwardingNumber(getCurrentVoicemailProviderKey(), 671 new VoiceMailProviderSettings(vmNum, fwdNum, fwdNumTime)); 672 return; 673 } 674 675 if (resultCode != RESULT_OK) { 676 if (DBG) log("onActivityResult: contact picker result not OK."); 677 return; 678 } 679 680 Cursor cursor = getContentResolver().query(data.getData(), 681 NUM_PROJECTION, null, null, null); 682 if ((cursor == null) || (!cursor.moveToFirst())) { 683 if (DBG) log("onActivityResult: bad contact data, no results found."); 684 return; 685 } 686 687 switch (requestCode) { 688 case VOICEMAIL_PREF_ID: 689 mSubMenuVoicemailSettings.onPickActivityResult(cursor.getString(0)); 690 break; 691 default: 692 // TODO: may need exception here. 693 } 694 } 695 696 // Voicemail button logic 697 private void handleVMBtnClickRequest() { 698 // normally called on the dialog close. 699 700 // Since we're stripping the formatting out on the getPhoneNumber() 701 // call now, we won't need to do so here anymore. 702 703 saveVoiceMailAndForwardingNumber( 704 getCurrentVoicemailProviderKey(), 705 new VoiceMailProviderSettings(mSubMenuVoicemailSettings.getPhoneNumber(), 706 FWD_SETTINGS_DONT_TOUCH)); 707 } 708 709 710 /** 711 * Wrapper around showDialog() that will silently do nothing if we're 712 * not in the foreground. 713 * 714 * This is useful here because most of the dialogs we display from 715 * this class are triggered by asynchronous events (like 716 * success/failure messages from the telephony layer) and it's 717 * possible for those events to come in even after the user has gone 718 * to a different screen. 719 */ 720 // TODO: this is too brittle: it's still easy to accidentally add new 721 // code here that calls showDialog() directly (which will result in a 722 // WindowManager$BadTokenException if called after the activity has 723 // been stopped.) 724 // 725 // It would be cleaner to do the "if (mForeground)" check in one 726 // central place, maybe by using a single Handler for all asynchronous 727 // events (and have *that* discard events if we're not in the 728 // foreground.) 729 // 730 // Unfortunately it's not that simple, since we sometimes need to do 731 // actual work to handle these events whether or not we're in the 732 // foreground (see the Handler code in mSetOptionComplete for 733 // example.) 734 private void showDialogIfForeground(int id) { 735 if (mForeground) { 736 showDialog(id); 737 } 738 } 739 740 private void dismissDialogSafely(int id) { 741 try { 742 dismissDialog(id); 743 } catch (IllegalArgumentException e) { 744 // This is expected in the case where we were in the background 745 // at the time we would normally have shown the dialog, so we didn't 746 // show it. 747 } 748 } 749 750 private void saveVoiceMailAndForwardingNumber(String key, 751 VoiceMailProviderSettings newSettings) { 752 if (DBG) log("saveVoiceMailAndForwardingNumber: " + newSettings.toString()); 753 mNewVMNumber = newSettings.voicemailNumber; 754 // empty vm number == clearing the vm number ? 755 if (mNewVMNumber == null) { 756 mNewVMNumber = ""; 757 } 758 759 mNewFwdSettings = newSettings.forwardingSettings; 760 if (DBG) log("newFwdNumber " + 761 String.valueOf((mNewFwdSettings != null ? mNewFwdSettings.length : 0)) 762 + " settings"); 763 764 // No fwd settings on CDMA 765 if (mPhone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { 766 if (DBG) log("ignoring forwarding setting since this is CDMA phone"); 767 mNewFwdSettings = FWD_SETTINGS_DONT_TOUCH; 768 } 769 770 //throw a warning if the vm is the same and we do not touch forwarding. 771 if (mNewVMNumber.equals(mOldVmNumber) && mNewFwdSettings == FWD_SETTINGS_DONT_TOUCH) { 772 showVMDialog(MSG_VM_NOCHANGE); 773 return; 774 } 775 776 maybeSaveSettingsForVoicemailProvider(key, newSettings); 777 mVMChangeCompletedSuccesfully = false; 778 mFwdChangesRequireRollback = false; 779 mVMOrFwdSetError = 0; 780 if (!key.equals(mPreviousVMProviderKey)) { 781 mReadingSettingsForDefaultProvider = 782 mPreviousVMProviderKey.equals(DEFAULT_VM_PROVIDER_KEY); 783 if (DBG) log("Reading current forwarding settings"); 784 mForwardingReadResults = new CallForwardInfo[FORWARDING_SETTINGS_REASONS.length]; 785 for (int i = 0; i < FORWARDING_SETTINGS_REASONS.length; i++) { 786 mForwardingReadResults[i] = null; 787 mPhone.getCallForwardingOption(FORWARDING_SETTINGS_REASONS[i], 788 mGetOptionComplete.obtainMessage(EVENT_FORWARDING_GET_COMPLETED, i, 0)); 789 } 790 showDialogIfForeground(VOICEMAIL_FWD_READING_DIALOG); 791 } else { 792 saveVoiceMailAndForwardingNumberStage2(); 793 } 794 } 795 796 private final Handler mGetOptionComplete = new Handler() { 797 @Override 798 public void handleMessage(Message msg) { 799 AsyncResult result = (AsyncResult) msg.obj; 800 switch (msg.what) { 801 case EVENT_FORWARDING_GET_COMPLETED: 802 handleForwardingSettingsReadResult(result, msg.arg1); 803 break; 804 } 805 } 806 }; 807 808 void handleForwardingSettingsReadResult(AsyncResult ar, int idx) { 809 if (DBG) Log.d(LOG_TAG, "handleForwardingSettingsReadResult: " + idx); 810 Throwable error = null; 811 if (ar.exception != null) { 812 if (DBG) Log.d(LOG_TAG, "FwdRead: ar.exception=" + 813 ar.exception.getMessage()); 814 error = ar.exception; 815 } 816 if (ar.userObj instanceof Throwable) { 817 if (DBG) Log.d(LOG_TAG, "FwdRead: userObj=" + 818 ((Throwable)ar.userObj).getMessage()); 819 error = (Throwable)ar.userObj; 820 } 821 822 // We may have already gotten an error and decided to ignore the other results. 823 if (mForwardingReadResults == null) { 824 if (DBG) Log.d(LOG_TAG, "ignoring fwd reading result: " + idx); 825 return; 826 } 827 828 // In case of error ignore other results, show an error dialog 829 if (error != null) { 830 if (DBG) Log.d(LOG_TAG, "Error discovered for fwd read : " + idx); 831 mForwardingReadResults = null; 832 dismissDialogSafely(VOICEMAIL_FWD_READING_DIALOG); 833 showVMDialog(MSG_FW_GET_EXCEPTION); 834 return; 835 } 836 837 // Get the forwarding info 838 final CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result; 839 CallForwardInfo fi = null; 840 for (int i = 0 ; i < cfInfoArray.length; i++) { 841 if ((cfInfoArray[i].serviceClass & CommandsInterface.SERVICE_CLASS_VOICE) != 0) { 842 fi = cfInfoArray[i]; 843 break; 844 } 845 } 846 if (fi == null) { 847 848 // In case we go nothing it means we need this reason disabled 849 // so create a CallForwardInfo for capturing this 850 if (DBG) Log.d(LOG_TAG, "Creating default info for " + idx); 851 fi = new CallForwardInfo(); 852 fi.status = 0; 853 fi.reason = FORWARDING_SETTINGS_REASONS[idx]; 854 fi.serviceClass = CommandsInterface.SERVICE_CLASS_VOICE; 855 } else { 856 // if there is not a forwarding number, ensure the entry is set to "not active." 857 if (fi.number == null || fi.number.length() == 0) { 858 fi.status = 0; 859 } 860 861 if (DBG) Log.d(LOG_TAG, "Got " + fi.toString() + " for " + idx); 862 } 863 mForwardingReadResults[idx] = fi; 864 865 // Check if we got all the results already 866 boolean done = true; 867 for (int i = 0; i < mForwardingReadResults.length; i++) { 868 if (mForwardingReadResults[i] == null) { 869 done = false; 870 break; 871 } 872 } 873 if (done) { 874 if (DBG) Log.d(LOG_TAG, "Done receiving fwd info"); 875 dismissDialogSafely(VOICEMAIL_FWD_READING_DIALOG); 876 if (mReadingSettingsForDefaultProvider) { 877 maybeSaveSettingsForVoicemailProvider(DEFAULT_VM_PROVIDER_KEY, 878 new VoiceMailProviderSettings(this.mOldVmNumber, 879 mForwardingReadResults)); 880 mReadingSettingsForDefaultProvider = false; 881 } 882 saveVoiceMailAndForwardingNumberStage2(); 883 } else { 884 if (DBG) Log.d(LOG_TAG, "Not done receiving fwd info"); 885 } 886 } 887 888 private CallForwardInfo infoForReason(CallForwardInfo[] infos, int reason) { 889 CallForwardInfo result = null; 890 if (null != infos) { 891 for (CallForwardInfo info : infos) { 892 if (info.reason == reason) { 893 result = info; 894 break; 895 } 896 } 897 } 898 return result; 899 } 900 901 private boolean isUpdateRequired(CallForwardInfo oldInfo, 902 CallForwardInfo newInfo) { 903 boolean result = true; 904 if (0 == newInfo.status) { 905 // If we're disabling a type of forwarding, and it's already 906 // disabled for the account, don't make any change 907 if (oldInfo != null && oldInfo.status == 0) { 908 result = false; 909 } 910 } 911 return result; 912 } 913 914 private void resetForwardingChangeState() { 915 mForwardingChangeResults = new HashMap<Integer, AsyncResult>(); 916 mExpectedChangeResultReasons = new HashSet<Integer>(); 917 } 918 919 // Called after we are done saving the previous forwarding settings if 920 // we needed. 921 private void saveVoiceMailAndForwardingNumberStage2() { 922 mForwardingChangeResults = null; 923 mVoicemailChangeResult = null; 924 if (mNewFwdSettings != FWD_SETTINGS_DONT_TOUCH) { 925 resetForwardingChangeState(); 926 for (int i = 0; i < mNewFwdSettings.length; i++) { 927 CallForwardInfo fi = mNewFwdSettings[i]; 928 929 final boolean doUpdate = isUpdateRequired(infoForReason( 930 mForwardingReadResults, fi.reason), fi); 931 932 if (doUpdate) { 933 if (DBG) log("Setting fwd #: " + i + ": " + fi.toString()); 934 mExpectedChangeResultReasons.add(i); 935 936 mPhone.setCallForwardingOption( 937 fi.status == 1 ? 938 CommandsInterface.CF_ACTION_REGISTRATION : 939 CommandsInterface.CF_ACTION_DISABLE, 940 fi.reason, 941 fi.number, 942 fi.timeSeconds, 943 mSetOptionComplete.obtainMessage( 944 EVENT_FORWARDING_CHANGED, fi.reason, 0)); 945 } 946 } 947 showDialogIfForeground(VOICEMAIL_FWD_SAVING_DIALOG); 948 } else { 949 if (DBG) log("Not touching fwd #"); 950 setVMNumberWithCarrier(); 951 } 952 } 953 954 void setVMNumberWithCarrier() { 955 if (DBG) log("save voicemail #: " + mNewVMNumber); 956 mPhone.setVoiceMailNumber( 957 mPhone.getVoiceMailAlphaTag().toString(), 958 mNewVMNumber, 959 Message.obtain(mSetOptionComplete, EVENT_VOICEMAIL_CHANGED)); 960 } 961 962 /** 963 * Callback to handle option update completions 964 */ 965 private final Handler mSetOptionComplete = new Handler() { 966 @Override 967 public void handleMessage(Message msg) { 968 AsyncResult result = (AsyncResult) msg.obj; 969 boolean done = false; 970 switch (msg.what) { 971 case EVENT_VOICEMAIL_CHANGED: 972 mVoicemailChangeResult = result; 973 mVMChangeCompletedSuccesfully = checkVMChangeSuccess() == null; 974 if (DBG) log("VM change complete msg, VM change done = " + 975 String.valueOf(mVMChangeCompletedSuccesfully)); 976 done = true; 977 break; 978 case EVENT_FORWARDING_CHANGED: 979 mForwardingChangeResults.put(msg.arg1, result); 980 if (result.exception != null) { 981 if (DBG) log("Error in setting fwd# " + msg.arg1 + ": " + 982 result.exception.getMessage()); 983 } else { 984 if (DBG) log("Success in setting fwd# " + msg.arg1); 985 } 986 final boolean completed = checkForwardingCompleted(); 987 if (completed) { 988 if (checkFwdChangeSuccess() == null) { 989 if (DBG) log("Overall fwd changes completed ok, starting vm change"); 990 setVMNumberWithCarrier(); 991 } else { 992 if (DBG) log("Overall fwd changes completed, failure"); 993 mFwdChangesRequireRollback = false; 994 Iterator<Map.Entry<Integer,AsyncResult>> it = 995 mForwardingChangeResults.entrySet().iterator(); 996 while (it.hasNext()) { 997 Map.Entry<Integer,AsyncResult> entry = it.next(); 998 if (entry.getValue().exception == null) { 999 // If at least one succeeded we have to revert 1000 if (DBG) log("Rollback will be required"); 1001 mFwdChangesRequireRollback =true; 1002 break; 1003 } 1004 } 1005 done = true; 1006 } 1007 } 1008 break; 1009 default: 1010 // TODO: should never reach this, may want to throw exception 1011 } 1012 if (done) { 1013 if (DBG) log("All VM provider related changes done"); 1014 if (mForwardingChangeResults != null) { 1015 dismissDialogSafely(VOICEMAIL_FWD_SAVING_DIALOG); 1016 } 1017 handleSetVMOrFwdMessage(); 1018 } 1019 } 1020 }; 1021 1022 /** 1023 * Callback to handle option revert completions 1024 */ 1025 private final Handler mRevertOptionComplete = new Handler() { 1026 @Override 1027 public void handleMessage(Message msg) { 1028 AsyncResult result = (AsyncResult) msg.obj; 1029 switch (msg.what) { 1030 case EVENT_VOICEMAIL_CHANGED: 1031 mVoicemailChangeResult = result; 1032 if (DBG) log("VM revert complete msg"); 1033 break; 1034 case EVENT_FORWARDING_CHANGED: 1035 mForwardingChangeResults.put(msg.arg1, result); 1036 if (result.exception != null) { 1037 if (DBG) log("Error in reverting fwd# " + msg.arg1 + ": " + 1038 result.exception.getMessage()); 1039 } else { 1040 if (DBG) log("Success in reverting fwd# " + msg.arg1); 1041 } 1042 if (DBG) log("FWD revert complete msg "); 1043 break; 1044 default: 1045 // TODO: should never reach this, may want to throw exception 1046 } 1047 final boolean done = 1048 (!mVMChangeCompletedSuccesfully || mVoicemailChangeResult != null) && 1049 (!mFwdChangesRequireRollback || checkForwardingCompleted()); 1050 if (done) { 1051 if (DBG) log("All VM reverts done"); 1052 dismissDialogSafely(VOICEMAIL_REVERTING_DIALOG); 1053 onRevertDone(); 1054 } 1055 } 1056 }; 1057 1058 /** 1059 * @return true if forwarding change has completed 1060 */ 1061 private boolean checkForwardingCompleted() { 1062 boolean result; 1063 if (mForwardingChangeResults == null) { 1064 result = true; 1065 } else { 1066 // return true iff there is a change result for every reason for 1067 // which we expected a result 1068 result = true; 1069 for (Integer reason : mExpectedChangeResultReasons) { 1070 if (mForwardingChangeResults.get(reason) == null) { 1071 result = false; 1072 break; 1073 } 1074 } 1075 } 1076 return result; 1077 } 1078 /** 1079 * @return error string or null if successful 1080 */ 1081 private String checkFwdChangeSuccess() { 1082 String result = null; 1083 Iterator<Map.Entry<Integer,AsyncResult>> it = 1084 mForwardingChangeResults.entrySet().iterator(); 1085 while (it.hasNext()) { 1086 Map.Entry<Integer,AsyncResult> entry = it.next(); 1087 Throwable exception = entry.getValue().exception; 1088 if (exception != null) { 1089 result = exception.getMessage(); 1090 if (result == null) { 1091 result = ""; 1092 } 1093 break; 1094 } 1095 } 1096 return result; 1097 } 1098 1099 /** 1100 * @return error string or null if successful 1101 */ 1102 private String checkVMChangeSuccess() { 1103 if (mVoicemailChangeResult.exception != null) { 1104 final String msg = mVoicemailChangeResult.exception.getMessage(); 1105 if (msg == null) { 1106 return ""; 1107 } 1108 return msg; 1109 } 1110 return null; 1111 } 1112 1113 private void handleSetVMOrFwdMessage() { 1114 if (DBG) { 1115 log("handleSetVMMessage: set VM request complete"); 1116 } 1117 boolean success = true; 1118 boolean fwdFailure = false; 1119 String exceptionMessage = ""; 1120 if (mForwardingChangeResults != null) { 1121 exceptionMessage = checkFwdChangeSuccess(); 1122 if (exceptionMessage != null) { 1123 success = false; 1124 fwdFailure = true; 1125 } 1126 } 1127 if (success) { 1128 exceptionMessage = checkVMChangeSuccess(); 1129 if (exceptionMessage != null) { 1130 success = false; 1131 } 1132 } 1133 if (success) { 1134 if (DBG) log("change VM success!"); 1135 handleVMAndFwdSetSuccess(MSG_VM_OK); 1136 updateVoiceNumberField(); 1137 } else { 1138 if (fwdFailure) { 1139 log("change FW failed: " + exceptionMessage); 1140 handleVMOrFwdSetError(MSG_FW_SET_EXCEPTION); 1141 } else { 1142 log("change VM failed: " + exceptionMessage); 1143 handleVMOrFwdSetError(MSG_VM_EXCEPTION); 1144 } 1145 } 1146 } 1147 1148 private void handleVMOrFwdSetError(int msgId) { 1149 if (mChangingVMorFwdDueToProviderChange) { 1150 mVMOrFwdSetError = msgId; 1151 mChangingVMorFwdDueToProviderChange = false; 1152 switchToPreviousVoicemailProvider(); 1153 return; 1154 } 1155 mChangingVMorFwdDueToProviderChange = false; 1156 showVMDialog(msgId); 1157 updateVoiceNumberField(); 1158 } 1159 1160 private void handleVMAndFwdSetSuccess(int msgId) { 1161 mChangingVMorFwdDueToProviderChange = false; 1162 showVMDialog(msgId); 1163 } 1164 1165 /* 1166 * Methods used to sync UI state with that of the network 1167 */ 1168 // update the voicemail number from what we've recorded on the sim. 1169 private void updateVoiceNumberField() { 1170 if (mSubMenuVoicemailSettings == null) { 1171 return; 1172 } 1173 1174 mOldVmNumber = mPhone.getVoiceMailNumber(); 1175 if (mOldVmNumber == null) { 1176 mOldVmNumber = ""; 1177 } 1178 mSubMenuVoicemailSettings.setPhoneNumber(mOldVmNumber); 1179 final String summary = (mOldVmNumber.length() > 0) ? mOldVmNumber : 1180 getString(R.string.voicemail_number_not_set); 1181 mSubMenuVoicemailSettings.setSummary(summary); 1182 } 1183 1184 /* 1185 * Helper Methods for Activity class. 1186 * The initial query commands are split into two pieces now 1187 * for individual expansion. This combined with the ability 1188 * to cancel queries allows for a much better user experience, 1189 * and also ensures that the user only waits to update the 1190 * data that is relevant. 1191 */ 1192 1193 @Override 1194 protected void onPrepareDialog(int id, Dialog dialog) { 1195 super.onPrepareDialog(id, dialog); 1196 mCurrentDialogId = id; 1197 } 1198 1199 // dialog creation method, called by showDialog() 1200 @Override 1201 protected Dialog onCreateDialog(int id) { 1202 if ((id == VM_RESPONSE_ERROR) || (id == VM_NOCHANGE_ERROR) || 1203 (id == FW_SET_RESPONSE_ERROR) || (id == FW_GET_RESPONSE_ERROR) || 1204 (id == VOICEMAIL_DIALOG_CONFIRM)) { 1205 1206 AlertDialog.Builder b = new AlertDialog.Builder(this); 1207 1208 int msgId; 1209 int titleId = R.string.error_updating_title; 1210 switch (id) { 1211 case VOICEMAIL_DIALOG_CONFIRM: 1212 msgId = R.string.vm_changed; 1213 titleId = R.string.voicemail; 1214 // Set Button 2 1215 b.setNegativeButton(R.string.close_dialog, this); 1216 break; 1217 case VM_NOCHANGE_ERROR: 1218 // even though this is technically an error, 1219 // keep the title friendly. 1220 msgId = R.string.no_change; 1221 titleId = R.string.voicemail; 1222 // Set Button 2 1223 b.setNegativeButton(R.string.close_dialog, this); 1224 break; 1225 case VM_RESPONSE_ERROR: 1226 msgId = R.string.vm_change_failed; 1227 // Set Button 1 1228 b.setPositiveButton(R.string.close_dialog, this); 1229 break; 1230 case FW_SET_RESPONSE_ERROR: 1231 msgId = R.string.fw_change_failed; 1232 // Set Button 1 1233 b.setPositiveButton(R.string.close_dialog, this); 1234 break; 1235 case FW_GET_RESPONSE_ERROR: 1236 msgId = R.string.fw_get_in_vm_failed; 1237 b.setPositiveButton(R.string.alert_dialog_yes, this); 1238 b.setNegativeButton(R.string.alert_dialog_no, this); 1239 break; 1240 default: 1241 msgId = R.string.exception_error; 1242 // Set Button 3, tells the activity that the error is 1243 // not recoverable on dialog exit. 1244 b.setNeutralButton(R.string.close_dialog, this); 1245 break; 1246 } 1247 1248 b.setTitle(getText(titleId)); 1249 String message = getText(msgId).toString(); 1250 b.setMessage(message); 1251 b.setCancelable(false); 1252 AlertDialog dialog = b.create(); 1253 1254 // make the dialog more obvious by bluring the background. 1255 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 1256 1257 return dialog; 1258 } else if (id == VOICEMAIL_FWD_SAVING_DIALOG || id == VOICEMAIL_FWD_READING_DIALOG || 1259 id == VOICEMAIL_REVERTING_DIALOG) { 1260 ProgressDialog dialog = new ProgressDialog(this); 1261 dialog.setTitle(getText(R.string.updating_title)); 1262 dialog.setIndeterminate(true); 1263 dialog.setCancelable(false); 1264 dialog.setMessage(getText( 1265 id == VOICEMAIL_FWD_SAVING_DIALOG ? R.string.updating_settings : 1266 (id == VOICEMAIL_REVERTING_DIALOG ? R.string.reverting_settings : 1267 R.string.reading_settings))); 1268 return dialog; 1269 } 1270 1271 1272 return null; 1273 } 1274 1275 // This is a method implemented for DialogInterface.OnClickListener. 1276 // Used with the error dialog to close the app, voicemail dialog to just dismiss. 1277 // Close button is mapped to BUTTON_POSITIVE for the errors that close the activity, 1278 // while those that are mapped to BUTTON_NEUTRAL only move the preference focus. 1279 public void onClick(DialogInterface dialog, int which) { 1280 dialog.dismiss(); 1281 switch (which){ 1282 case DialogInterface.BUTTON_NEUTRAL: 1283 if (DBG) log("Neutral button"); 1284 break; 1285 case DialogInterface.BUTTON_NEGATIVE: 1286 if (DBG) log("Negative button"); 1287 if (mCurrentDialogId == FW_GET_RESPONSE_ERROR) { 1288 // We failed to get current forwarding settings and the user 1289 // does not wish to continue. 1290 switchToPreviousVoicemailProvider(); 1291 } 1292 break; 1293 case DialogInterface.BUTTON_POSITIVE: 1294 if (DBG) log("Positive button"); 1295 if (mCurrentDialogId == FW_GET_RESPONSE_ERROR) { 1296 // We failed to get current forwarding settings but the user 1297 // wishes to continue changing settings to the new vm provider 1298 saveVoiceMailAndForwardingNumberStage2(); 1299 } else { 1300 finish(); 1301 } 1302 return; 1303 default: 1304 // just let the dialog close and go back to the input 1305 } 1306 // In all dialogs, all buttons except BUTTON_POSITIVE lead to the end of user interaction 1307 // with settings UI. If we were called to explicitly configure voice mail then 1308 // we finish the settings activity here to come back to whatever the user was doing. 1309 if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) { 1310 finish(); 1311 } 1312 } 1313 1314 // set the app state with optional status. 1315 private void showVMDialog(int msgStatus) { 1316 switch (msgStatus) { 1317 // It's a bit worrisome to punt in the error cases here when we're 1318 // not in the foreground; maybe toast instead? 1319 case MSG_VM_EXCEPTION: 1320 showDialogIfForeground(VM_RESPONSE_ERROR); 1321 break; 1322 case MSG_FW_SET_EXCEPTION: 1323 showDialogIfForeground(FW_SET_RESPONSE_ERROR); 1324 break; 1325 case MSG_FW_GET_EXCEPTION: 1326 showDialogIfForeground(FW_GET_RESPONSE_ERROR); 1327 break; 1328 case MSG_VM_NOCHANGE: 1329 showDialogIfForeground(VM_NOCHANGE_ERROR); 1330 break; 1331 case MSG_VM_OK: 1332 showDialogIfForeground(VOICEMAIL_DIALOG_CONFIRM); 1333 break; 1334 case MSG_OK: 1335 default: 1336 // This should never happen. 1337 } 1338 } 1339 1340 /* 1341 * Activity class methods 1342 */ 1343 1344 @Override 1345 protected void onCreate(Bundle icicle) { 1346 super.onCreate(icicle); 1347 if (DBG) log("Creating activity"); 1348 mPhone = PhoneFactory.getDefaultPhone(); 1349 1350 addPreferencesFromResource(R.xml.call_feature_setting); 1351 1352 mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 1353 1354 // get buttons 1355 PreferenceScreen prefSet = getPreferenceScreen(); 1356 mSubMenuVoicemailSettings = (EditPhoneNumberPreference)findPreference(BUTTON_VOICEMAIL_KEY); 1357 if (mSubMenuVoicemailSettings != null) { 1358 mSubMenuVoicemailSettings.setParentActivity(this, VOICEMAIL_PREF_ID, this); 1359 mSubMenuVoicemailSettings.setDialogOnClosedListener(this); 1360 mSubMenuVoicemailSettings.setDialogTitle(R.string.voicemail_settings_number_label); 1361 } 1362 1363 mButtonDTMF = (ListPreference) findPreference(BUTTON_DTMF_KEY); 1364 mButtonAutoRetry = (CheckBoxPreference) findPreference(BUTTON_RETRY_KEY); 1365 mButtonHAC = (CheckBoxPreference) findPreference(BUTTON_HAC_KEY); 1366 mButtonTTY = (ListPreference) findPreference(BUTTON_TTY_KEY); 1367 mVoicemailProviders = (ListPreference) findPreference(BUTTON_VOICEMAIL_PROVIDER_KEY); 1368 if (mVoicemailProviders != null) { 1369 mVoicemailProviders.setOnPreferenceChangeListener(this); 1370 mVoicemailSettings = (PreferenceScreen)findPreference(BUTTON_VOICEMAIL_SETTING_KEY); 1371 1372 initVoiceMailProviders(); 1373 } 1374 1375 if (mButtonDTMF != null) { 1376 if (getResources().getBoolean(R.bool.dtmf_type_enabled)) { 1377 mButtonDTMF.setOnPreferenceChangeListener(this); 1378 } else { 1379 prefSet.removePreference(mButtonDTMF); 1380 mButtonDTMF = null; 1381 } 1382 } 1383 1384 if (mButtonAutoRetry != null) { 1385 if (getResources().getBoolean(R.bool.auto_retry_enabled)) { 1386 mButtonAutoRetry.setOnPreferenceChangeListener(this); 1387 } else { 1388 prefSet.removePreference(mButtonAutoRetry); 1389 mButtonAutoRetry = null; 1390 } 1391 } 1392 1393 if (mButtonHAC != null) { 1394 if (getResources().getBoolean(R.bool.hac_enabled)) { 1395 1396 mButtonHAC.setOnPreferenceChangeListener(this); 1397 } else { 1398 prefSet.removePreference(mButtonHAC); 1399 mButtonHAC = null; 1400 } 1401 } 1402 1403 if (mButtonTTY != null) { 1404 if (getResources().getBoolean(R.bool.tty_enabled)) { 1405 mButtonTTY.setOnPreferenceChangeListener(this); 1406 } else { 1407 prefSet.removePreference(mButtonTTY); 1408 mButtonTTY = null; 1409 } 1410 } 1411 1412 if (!getResources().getBoolean(R.bool.world_phone)) { 1413 Preference options = prefSet.findPreference(BUTTON_CDMA_OPTIONS); 1414 if (options != null) 1415 prefSet.removePreference(options); 1416 options = prefSet.findPreference(BUTTON_GSM_UMTS_OPTIONS); 1417 if (options != null) 1418 prefSet.removePreference(options); 1419 1420 int phoneType = mPhone.getPhoneType(); 1421 if (phoneType == Phone.PHONE_TYPE_CDMA) { 1422 Preference fdnButton = prefSet.findPreference(BUTTON_FDN_KEY); 1423 if (fdnButton != null) 1424 prefSet.removePreference(fdnButton); 1425 if (!getResources().getBoolean(R.bool.config_voice_privacy_disable)) { 1426 addPreferencesFromResource(R.xml.cdma_call_privacy); 1427 } 1428 } else if (phoneType == Phone.PHONE_TYPE_GSM) { 1429 addPreferencesFromResource(R.xml.gsm_umts_call_options); 1430 } else { 1431 throw new IllegalStateException("Unexpected phone type: " + phoneType); 1432 } 1433 } 1434 1435 // create intent to bring up contact list 1436 mContactListIntent = new Intent(Intent.ACTION_GET_CONTENT); 1437 mContactListIntent.setType(android.provider.Contacts.Phones.CONTENT_ITEM_TYPE); 1438 1439 // check the intent that started this activity and pop up the voicemail 1440 // dialog if we've been asked to. 1441 // If we have at least one non default VM provider registered then bring up 1442 // the selection for the VM provider, otherwise bring up a VM number dialog. 1443 // We only bring up the dialog the first time we are called (not after orientation change) 1444 if (icicle == null) { 1445 if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL) && 1446 mVoicemailProviders != null) { 1447 if (mVMProvidersData.size() > 1) { 1448 simulatePreferenceClick(mVoicemailProviders); 1449 } else { 1450 onPreferenceChange(mVoicemailProviders, DEFAULT_VM_PROVIDER_KEY); 1451 mVoicemailProviders.setValue(DEFAULT_VM_PROVIDER_KEY); 1452 } 1453 } 1454 } 1455 updateVoiceNumberField(); 1456 mVMProviderSettingsForced = false; 1457 createSipCallSettings(); 1458 } 1459 1460 private void createSipCallSettings() { 1461 // Add Internet call settings. 1462 if (SipManager.isVoipSupported(this)) { 1463 mSipManager = SipManager.newInstance(this); 1464 mSipSharedPreferences = new SipSharedPreferences(this); 1465 addPreferencesFromResource(R.xml.sip_settings_category); 1466 mButtonSipCallOptions = getSipCallOptionPreference(); 1467 mButtonSipCallOptions.setOnPreferenceChangeListener(this); 1468 mButtonSipCallOptions.setValueIndex( 1469 mButtonSipCallOptions.findIndexOfValue( 1470 mSipSharedPreferences.getSipCallOption())); 1471 mButtonSipCallOptions.setSummary(mButtonSipCallOptions.getEntry()); 1472 } 1473 } 1474 1475 // Gets the call options for SIP depending on whether SIP is allowed only 1476 // on Wi-Fi only; also make the other options preference invisible. 1477 private ListPreference getSipCallOptionPreference() { 1478 ListPreference wifiAnd3G = (ListPreference) 1479 findPreference(BUTTON_SIP_CALL_OPTIONS); 1480 ListPreference wifiOnly = (ListPreference) 1481 findPreference(BUTTON_SIP_CALL_OPTIONS_WIFI_ONLY); 1482 PreferenceGroup sipSettings = (PreferenceGroup) 1483 findPreference(SIP_SETTINGS_CATEGORY_KEY); 1484 if (SipManager.isSipWifiOnly(this)) { 1485 sipSettings.removePreference(wifiAnd3G); 1486 return wifiOnly; 1487 } else { 1488 sipSettings.removePreference(wifiOnly); 1489 return wifiAnd3G; 1490 } 1491 } 1492 1493 @Override 1494 protected void onResume() { 1495 super.onResume(); 1496 mForeground = true; 1497 1498 if (isAirplaneModeOn()) { 1499 Preference sipSettings = findPreference(SIP_SETTINGS_CATEGORY_KEY); 1500 PreferenceScreen screen = getPreferenceScreen(); 1501 int count = screen.getPreferenceCount(); 1502 for (int i = 0 ; i < count ; ++i) { 1503 Preference pref = screen.getPreference(i); 1504 if (pref != sipSettings) pref.setEnabled(false); 1505 } 1506 return; 1507 } 1508 1509 if (mButtonDTMF != null) { 1510 int dtmf = Settings.System.getInt(getContentResolver(), 1511 Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_NORMAL); 1512 mButtonDTMF.setValueIndex(dtmf); 1513 } 1514 1515 if (mButtonAutoRetry != null) { 1516 int autoretry = Settings.System.getInt(getContentResolver(), 1517 Settings.System.CALL_AUTO_RETRY, 0); 1518 mButtonAutoRetry.setChecked(autoretry != 0); 1519 } 1520 1521 if (mButtonHAC != null) { 1522 int hac = Settings.System.getInt(getContentResolver(), Settings.System.HEARING_AID, 0); 1523 mButtonHAC.setChecked(hac != 0); 1524 } 1525 1526 if (mButtonTTY != null) { 1527 int settingsTtyMode = Settings.Secure.getInt(getContentResolver(), 1528 Settings.Secure.PREFERRED_TTY_MODE, 1529 Phone.TTY_MODE_OFF); 1530 mButtonTTY.setValue(Integer.toString(settingsTtyMode)); 1531 updatePreferredTtyModeSummary(settingsTtyMode); 1532 } 1533 } 1534 1535 private boolean isAirplaneModeOn() { 1536 return Settings.System.getInt(getContentResolver(), 1537 Settings.System.AIRPLANE_MODE_ON, 0) != 0; 1538 } 1539 1540 private void handleTTYChange(Preference preference, Object objValue) { 1541 int buttonTtyMode; 1542 buttonTtyMode = Integer.valueOf((String) objValue).intValue(); 1543 int settingsTtyMode = android.provider.Settings.Secure.getInt( 1544 getContentResolver(), 1545 android.provider.Settings.Secure.PREFERRED_TTY_MODE, preferredTtyMode); 1546 if (DBG) log("handleTTYChange: requesting set TTY mode enable (TTY) to" + 1547 Integer.toString(buttonTtyMode)); 1548 1549 if (buttonTtyMode != settingsTtyMode) { 1550 switch(buttonTtyMode) { 1551 case Phone.TTY_MODE_OFF: 1552 case Phone.TTY_MODE_FULL: 1553 case Phone.TTY_MODE_HCO: 1554 case Phone.TTY_MODE_VCO: 1555 android.provider.Settings.Secure.putInt(getContentResolver(), 1556 android.provider.Settings.Secure.PREFERRED_TTY_MODE, buttonTtyMode); 1557 break; 1558 default: 1559 buttonTtyMode = Phone.TTY_MODE_OFF; 1560 } 1561 1562 mButtonTTY.setValue(Integer.toString(buttonTtyMode)); 1563 updatePreferredTtyModeSummary(buttonTtyMode); 1564 Intent ttyModeChanged = new Intent(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION); 1565 ttyModeChanged.putExtra(TtyIntent.TTY_PREFFERED_MODE, buttonTtyMode); 1566 sendBroadcast(ttyModeChanged); 1567 } 1568 } 1569 1570 private void handleSipCallOptionsChange(Object objValue) { 1571 String option = objValue.toString(); 1572 mSipSharedPreferences.setSipCallOption(option); 1573 mButtonSipCallOptions.setValueIndex( 1574 mButtonSipCallOptions.findIndexOfValue(option)); 1575 mButtonSipCallOptions.setSummary(mButtonSipCallOptions.getEntry()); 1576 } 1577 1578 private void updatePreferredTtyModeSummary(int TtyMode) { 1579 String [] txts = getResources().getStringArray(R.array.tty_mode_entries); 1580 switch(TtyMode) { 1581 case Phone.TTY_MODE_OFF: 1582 case Phone.TTY_MODE_HCO: 1583 case Phone.TTY_MODE_VCO: 1584 case Phone.TTY_MODE_FULL: 1585 mButtonTTY.setSummary(txts[TtyMode]); 1586 break; 1587 default: 1588 mButtonTTY.setEnabled(false); 1589 mButtonTTY.setSummary(txts[Phone.TTY_MODE_OFF]); 1590 } 1591 } 1592 1593 private static void log(String msg) { 1594 Log.d(LOG_TAG, msg); 1595 } 1596 1597 /** 1598 * Updates the look of the VM preference widgets based on current VM provider settings. 1599 * Note that the provider name is loaded form the found activity via loadLabel in 1600 * initVoiceMailProviders in order for it to be localizable. 1601 */ 1602 private void updateVMPreferenceWidgets(String currentProviderSetting) { 1603 final String key = currentProviderSetting; 1604 final VoiceMailProvider provider = mVMProvidersData.get(key); 1605 1606 /* This is the case when we are coming up on a freshly wiped phone and there is no 1607 persisted value for the list preference mVoicemailProviders. 1608 In this case we want to show the UI asking the user to select a voicemail provider as 1609 opposed to silently falling back to default one. */ 1610 if (provider == null) { 1611 mVoicemailProviders.setSummary(getString(R.string.sum_voicemail_choose_provider)); 1612 mVoicemailSettings.setSummary(""); 1613 mVoicemailSettings.setEnabled(false); 1614 mVoicemailSettings.setIntent(null); 1615 } else { 1616 final String providerName = provider.name; 1617 mVoicemailProviders.setSummary(providerName); 1618 mVoicemailSettings.setSummary(getApplicationContext().getString( 1619 R.string.voicemail_settings_for, providerName)); 1620 mVoicemailSettings.setEnabled(true); 1621 mVoicemailSettings.setIntent(provider.intent); 1622 } 1623 } 1624 1625 /** 1626 * Enumerates existing VM providers and puts their data into the list and populates 1627 * the preference list objects with their names. 1628 * In case we are called with ACTION_ADD_VOICEMAIL intent the intent may have 1629 * an extra string called IGNORE_PROVIDER_EXTRA with "package.activityName" of the provider 1630 * which should be hidden when we bring up the list of possible VM providers to choose. 1631 * This allows a provider which is being disabled (e.g. GV user logging out) to force the user 1632 * to pick some other provider. 1633 */ 1634 private void initVoiceMailProviders() { 1635 mPerProviderSavedVMNumbers = 1636 this.getApplicationContext().getSharedPreferences( 1637 VM_NUMBERS_SHARED_PREFERENCES_NAME, MODE_PRIVATE); 1638 1639 String providerToIgnore = null; 1640 if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) { 1641 if (DBG) log("ACTION_ADD_VOICEMAIL"); 1642 if (getIntent().hasExtra(IGNORE_PROVIDER_EXTRA)) { 1643 providerToIgnore = getIntent().getStringExtra(IGNORE_PROVIDER_EXTRA); 1644 } 1645 if (DBG) log("providerToIgnore=" + providerToIgnore); 1646 if (providerToIgnore != null) { 1647 deleteSettingsForVoicemailProvider(providerToIgnore); 1648 } 1649 } 1650 1651 mVMProvidersData.clear(); 1652 1653 // Stick the default element which is always there 1654 final String myCarrier = getString(R.string.voicemail_default); 1655 mVMProvidersData.put(DEFAULT_VM_PROVIDER_KEY, new VoiceMailProvider(myCarrier, null)); 1656 1657 // Enumerate providers 1658 PackageManager pm = getPackageManager(); 1659 Intent intent = new Intent(); 1660 intent.setAction(ACTION_CONFIGURE_VOICEMAIL); 1661 List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0); 1662 int len = resolveInfos.size() + 1; // +1 for the default choice we will insert. 1663 1664 // Go through the list of discovered providers populating the data map 1665 // skip the provider we were instructed to ignore if there was one 1666 for (int i = 0; i < resolveInfos.size(); i++) { 1667 final ResolveInfo ri= resolveInfos.get(i); 1668 final ActivityInfo currentActivityInfo = ri.activityInfo; 1669 final String key = makeKeyForActivity(currentActivityInfo); 1670 if (DBG) log("Loading " + key); 1671 if (key.equals(providerToIgnore)) { 1672 if (DBG) log("Ignoring " + key); 1673 len--; 1674 continue; 1675 } 1676 final String nameForDisplay = ri.loadLabel(pm).toString(); 1677 Intent providerIntent = new Intent(); 1678 providerIntent.setAction(ACTION_CONFIGURE_VOICEMAIL); 1679 providerIntent.setClassName(currentActivityInfo.packageName, 1680 currentActivityInfo.name); 1681 mVMProvidersData.put( 1682 key, 1683 new VoiceMailProvider(nameForDisplay, providerIntent)); 1684 1685 } 1686 1687 // Now we know which providers to display - create entries and values array for 1688 // the list preference 1689 String [] entries = new String [len]; 1690 String [] values = new String [len]; 1691 entries[0] = myCarrier; 1692 values[0] = DEFAULT_VM_PROVIDER_KEY; 1693 int entryIdx = 1; 1694 for (int i = 0; i < resolveInfos.size(); i++) { 1695 final String key = makeKeyForActivity(resolveInfos.get(i).activityInfo); 1696 if (!mVMProvidersData.containsKey(key)) { 1697 continue; 1698 } 1699 entries[entryIdx] = mVMProvidersData.get(key).name; 1700 values[entryIdx] = key; 1701 entryIdx++; 1702 } 1703 1704 mVoicemailProviders.setEntries(entries); 1705 mVoicemailProviders.setEntryValues(values); 1706 1707 mPreviousVMProviderKey = getCurrentVoicemailProviderKey(); 1708 updateVMPreferenceWidgets(mPreviousVMProviderKey); 1709 } 1710 1711 private String makeKeyForActivity(ActivityInfo ai) { 1712 return ai.name; 1713 } 1714 1715 /** 1716 * Simulates user clicking on a passed preference. 1717 * Usually needed when the preference is a dialog preference and we want to invoke 1718 * a dialog for this preference programmatically. 1719 * TODO(iliat): figure out if there is a cleaner way to cause preference dlg to come up 1720 */ 1721 private void simulatePreferenceClick(Preference preference) { 1722 // Go through settings until we find our setting 1723 // and then simulate a click on it to bring up the dialog 1724 final ListAdapter adapter = getPreferenceScreen().getRootAdapter(); 1725 for (int idx = 0; idx < adapter.getCount(); idx++) { 1726 if (adapter.getItem(idx) == preference) { 1727 getPreferenceScreen().onItemClick(this.getListView(), 1728 null, idx, adapter.getItemId(idx)); 1729 break; 1730 } 1731 } 1732 } 1733 1734 /** 1735 * Saves new VM provider settings associating them with the currently selected 1736 * provider if settings are different than the ones already stored for this 1737 * provider. 1738 * Later on these will be used when the user switches a provider. 1739 */ 1740 private void maybeSaveSettingsForVoicemailProvider(String key, 1741 VoiceMailProviderSettings newSettings) { 1742 if (mVoicemailProviders == null) { 1743 return; 1744 } 1745 final VoiceMailProviderSettings curSettings = loadSettingsForVoiceMailProvider(key); 1746 if (newSettings.equals(curSettings)) { 1747 if (DBG) log("Not saving setting for " + key + " since they have not changed"); 1748 return; 1749 } 1750 if (DBG) log("Saving settings for " + key + ": " + newSettings.toString()); 1751 Editor editor = mPerProviderSavedVMNumbers.edit(); 1752 editor.putString(key + VM_NUMBER_TAG,newSettings.voicemailNumber); 1753 String fwdKey = key + FWD_SETTINGS_TAG; 1754 CallForwardInfo[] s = newSettings.forwardingSettings; 1755 if (s != FWD_SETTINGS_DONT_TOUCH) { 1756 editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, s.length); 1757 for (int i = 0; i < s.length; i++) { 1758 final String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i); 1759 final CallForwardInfo fi = s[i]; 1760 editor.putInt(settingKey + FWD_SETTING_STATUS, fi.status); 1761 editor.putInt(settingKey + FWD_SETTING_REASON, fi.reason); 1762 editor.putString(settingKey + FWD_SETTING_NUMBER, fi.number); 1763 editor.putInt(settingKey + FWD_SETTING_TIME, fi.timeSeconds); 1764 } 1765 } else { 1766 editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0); 1767 } 1768 editor.apply(); 1769 } 1770 1771 /** 1772 * Returns settings previously stored for the currently selected 1773 * voice mail provider. If none is stored returns null. 1774 * If the user switches to a voice mail provider and we have settings 1775 * stored for it we will automatically change the phone's voice mail number 1776 * and forwarding number to the stored one. Otherwise we will bring up provider's configuration 1777 * UI. 1778 */ 1779 private VoiceMailProviderSettings loadSettingsForVoiceMailProvider(String key) { 1780 final String vmNumberSetting = mPerProviderSavedVMNumbers.getString(key + VM_NUMBER_TAG, 1781 null); 1782 if (vmNumberSetting == null) { 1783 if (DBG) log("Settings for " + key + " not found"); 1784 return null; 1785 } 1786 1787 CallForwardInfo[] cfi = FWD_SETTINGS_DONT_TOUCH; 1788 String fwdKey = key + FWD_SETTINGS_TAG; 1789 final int fwdLen = mPerProviderSavedVMNumbers.getInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0); 1790 if (fwdLen > 0) { 1791 cfi = new CallForwardInfo[fwdLen]; 1792 for (int i = 0; i < cfi.length; i++) { 1793 final String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i); 1794 cfi[i] = new CallForwardInfo(); 1795 cfi[i].status = mPerProviderSavedVMNumbers.getInt( 1796 settingKey + FWD_SETTING_STATUS, 0); 1797 cfi[i].reason = mPerProviderSavedVMNumbers.getInt( 1798 settingKey + FWD_SETTING_REASON, 1799 CommandsInterface.CF_REASON_ALL_CONDITIONAL); 1800 cfi[i].serviceClass = CommandsInterface.SERVICE_CLASS_VOICE; 1801 cfi[i].toa = PhoneNumberUtils.TOA_International; 1802 cfi[i].number = mPerProviderSavedVMNumbers.getString( 1803 settingKey + FWD_SETTING_NUMBER, ""); 1804 cfi[i].timeSeconds = mPerProviderSavedVMNumbers.getInt( 1805 settingKey + FWD_SETTING_TIME, 20); 1806 } 1807 } 1808 1809 VoiceMailProviderSettings settings = new VoiceMailProviderSettings(vmNumberSetting, cfi); 1810 if (DBG) log("Loaded settings for " + key + ": " + settings.toString()); 1811 return settings; 1812 } 1813 1814 /** 1815 * Deletes settings for the specified provider. 1816 */ 1817 private void deleteSettingsForVoicemailProvider(String key) { 1818 if (DBG) log("Deleting settings for" + key); 1819 if (mVoicemailProviders == null) { 1820 return; 1821 } 1822 mPerProviderSavedVMNumbers.edit() 1823 .putString(key + VM_NUMBER_TAG, null) 1824 .putInt(key + FWD_SETTINGS_TAG + FWD_SETTINGS_LENGTH_TAG, 0) 1825 .commit(); 1826 } 1827 1828 private String getCurrentVoicemailProviderKey() { 1829 final String key = mVoicemailProviders.getValue(); 1830 return (key != null) ? key : DEFAULT_VM_PROVIDER_KEY; 1831 } 1832 } 1833