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