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