blob: e46802732e603bdefdfa7879c54938df1c343bde [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
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
17package com.android.phone;
18
19import android.app.ActionBar;
20import android.app.Activity;
Evan Charlton1c696832014-04-15 14:24:23 -070021import android.app.ActivityOptions;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070022import android.app.AlertDialog;
23import android.app.Dialog;
24import android.app.ProgressDialog;
25import android.content.ContentResolver;
26import android.content.Context;
27import android.content.DialogInterface;
28import android.content.Intent;
29import android.content.SharedPreferences;
30import android.content.SharedPreferences.Editor;
31import android.content.pm.ActivityInfo;
32import android.content.pm.PackageManager;
33import android.content.pm.ResolveInfo;
34import android.database.Cursor;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070035import android.media.AudioManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070036import android.os.AsyncResult;
37import android.os.Bundle;
38import android.os.Handler;
39import android.os.Message;
40import android.os.UserHandle;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070041import android.preference.CheckBoxPreference;
42import android.preference.ListPreference;
43import android.preference.Preference;
44import android.preference.PreferenceActivity;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070045import android.preference.PreferenceManager;
46import android.preference.PreferenceScreen;
47import android.provider.ContactsContract.CommonDataKinds;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070048import android.provider.Settings;
Tyler Gunn4d45d1c2014-09-12 22:17:53 -070049import android.telecom.PhoneAccountHandle;
50import android.telecom.TelecomManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070051import android.telephony.PhoneNumberUtils;
Andrew Lee93c345f2014-10-27 15:25:07 -070052import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070053import android.text.TextUtils;
54import android.util.Log;
55import android.view.MenuItem;
56import android.view.WindowManager;
57import android.widget.ListAdapter;
58
Andrew Lee312e8172014-10-23 17:01:36 -070059import com.android.ims.ImsManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070060import com.android.internal.telephony.CallForwardInfo;
61import com.android.internal.telephony.CommandsInterface;
62import com.android.internal.telephony.Phone;
63import com.android.internal.telephony.PhoneConstants;
Andrew Lee2170a972014-08-13 18:13:01 -070064import com.android.phone.common.util.SettingsUtil;
Andrew Leedb2fe562014-09-03 15:40:43 -070065import com.android.phone.settings.AccountSelectionPreference;
Andrew Leeb490d732014-10-27 15:00:41 -070066import com.android.phone.settings.VoicemailProviderSettings;
Sailesh Nepal788959e2014-07-08 23:36:40 -070067import com.android.services.telephony.sip.SipUtil;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070068
Andrew Lee2170a972014-08-13 18:13:01 -070069import java.lang.String;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070070import java.util.Collection;
71import java.util.HashMap;
72import java.util.HashSet;
73import java.util.Iterator;
74import java.util.List;
75import java.util.Map;
76
77/**
78 * Top level "Call settings" UI; see res/xml/call_feature_setting.xml
79 *
Andrew Leece8ae2a2014-09-10 10:41:48 -070080 * This preference screen is the root of the "Call settings" hierarchy available from the Phone
81 * app; the settings here let you control various features related to phone calls (including
82 * voicemail settings, the "Respond via SMS" feature, and others.) It's used only on
83 * voice-capable phone devices.
Santos Cordon7d4ddf62013-07-10 11:58:08 -070084 *
85 * Note that this activity is part of the package com.android.phone, even
86 * though you reach it from the "Phone" app (i.e. DialtactsActivity) which
87 * is from the package com.android.contacts.
88 *
89 * For the "Mobile network settings" screen under the main Settings app,
90 * See {@link MobileNetworkSettings}.
91 *
Andrew Leece8ae2a2014-09-10 10:41:48 -070092 * TODO: Settings should be split into PreferenceFragments where possible (ie. voicemail).
Andrew Lee2170a972014-08-13 18:13:01 -070093 *
Santos Cordon7d4ddf62013-07-10 11:58:08 -070094 * @see com.android.phone.MobileNetworkSettings
95 */
96public class CallFeaturesSetting extends PreferenceActivity
97 implements DialogInterface.OnClickListener,
Andrew Lee2170a972014-08-13 18:13:01 -070098 Preference.OnPreferenceChangeListener,
Andrew Lee2170a972014-08-13 18:13:01 -070099 EditPhoneNumberPreference.OnDialogClosedListener,
Andrew Leece8ae2a2014-09-10 10:41:48 -0700100 EditPhoneNumberPreference.GetDefaultNumberListener {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700101 private static final String LOG_TAG = "CallFeaturesSetting";
102 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
Andrew Lee77527ac2014-10-21 16:57:39 -0700103 // STOPSHIP if true. Flag to override behavior default behavior to hide VT setting.
104 private static final boolean ENABLE_VT_FLAG = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700105
106 /**
107 * Intent action to bring up Voicemail Provider settings.
108 *
109 * @see #IGNORE_PROVIDER_EXTRA
110 */
111 public static final String ACTION_ADD_VOICEMAIL =
112 "com.android.phone.CallFeaturesSetting.ADD_VOICEMAIL";
113 // intent action sent by this activity to a voice mail provider
114 // to trigger its configuration UI
115 public static final String ACTION_CONFIGURE_VOICEMAIL =
116 "com.android.phone.CallFeaturesSetting.CONFIGURE_VOICEMAIL";
Andrew Leee3c15212014-10-28 13:12:55 -0700117 // Extra on intent to Call Settings containing the id of the subscription to modify.
118 public static final String SUB_ID_EXTRA =
119 "com.android.phone.CallFeaturesSetting.SubscriptionId";
120 // Extra on intent to Call Settings containing the label of the subscription to modify.
121 public static final String SUB_LABEL_EXTRA =
122 "com.android.phone.CallFeaturesSetting.SubscriptionLabel";
123
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700124 // Extra put in the return from VM provider config containing voicemail number to set
125 public static final String VM_NUMBER_EXTRA = "com.android.phone.VoicemailNumber";
126 // Extra put in the return from VM provider config containing call forwarding number to set
127 public static final String FWD_NUMBER_EXTRA = "com.android.phone.ForwardingNumber";
128 // Extra put in the return from VM provider config containing call forwarding number to set
129 public static final String FWD_NUMBER_TIME_EXTRA = "com.android.phone.ForwardingNumberTime";
130 // If the VM provider returns non null value in this extra we will force the user to
131 // choose another VM provider
132 public static final String SIGNOUT_EXTRA = "com.android.phone.Signout";
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700133
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700134 // Suffix appended to provider key for storing vm number
135 public static final String VM_NUMBER_TAG = "#VMNumber";
136 // Suffix appended to provider key for storing forwarding settings
137 public static final String FWD_SETTINGS_TAG = "#FWDSettings";
138 // Suffix appended to forward settings key for storing length of settings array
139 public static final String FWD_SETTINGS_LENGTH_TAG = "#Length";
140 // Suffix appended to forward settings key for storing an individual setting
141 public static final String FWD_SETTING_TAG = "#Setting";
142 // Suffixes appended to forward setting key for storing an individual setting properties
143 public static final String FWD_SETTING_STATUS = "#Status";
144 public static final String FWD_SETTING_REASON = "#Reason";
145 public static final String FWD_SETTING_NUMBER = "#Number";
146 public static final String FWD_SETTING_TIME = "#Time";
147
148 // Key identifying the default vocie mail provider
149 public static final String DEFAULT_VM_PROVIDER_KEY = "";
150
151 /**
152 * String Extra put into ACTION_ADD_VOICEMAIL call to indicate which provider should be hidden
153 * in the list of providers presented to the user. This allows a provider which is being
154 * disabled (e.g. GV user logging out) to force the user to pick some other provider.
155 */
156 public static final String IGNORE_PROVIDER_EXTRA = "com.android.phone.ProviderToIgnore";
157
158 // string constants
159 private static final String NUM_PROJECTION[] = {CommonDataKinds.Phone.NUMBER};
160
161 // String keys for preference lookup
162 // TODO: Naming these "BUTTON_*" is confusing since they're not actually buttons(!)
Andrew Lee97708a42014-09-25 12:39:07 -0700163 private static final String VOICEMAIL_SETTING_SCREEN_PREF_KEY = "button_voicemail_category_key";
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700164 private static final String BUTTON_VOICEMAIL_KEY = "button_voicemail_key";
165 private static final String BUTTON_VOICEMAIL_PROVIDER_KEY = "button_voicemail_provider_key";
166 private static final String BUTTON_VOICEMAIL_SETTING_KEY = "button_voicemail_setting_key";
167 // New preference key for voicemail notification vibration
168 /* package */ static final String BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY =
169 "button_voicemail_notification_vibrate_key";
170 // Old preference key for voicemail notification vibration. Used for migration to the new
171 // preference key only.
172 /* package */ static final String BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_WHEN_KEY =
173 "button_voicemail_notification_vibrate_when_key";
174 /* package */ static final String BUTTON_VOICEMAIL_NOTIFICATION_RINGTONE_KEY =
175 "button_voicemail_notification_ringtone_key";
176 private static final String BUTTON_FDN_KEY = "button_fdn_key";
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700177
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700178 private static final String BUTTON_DTMF_KEY = "button_dtmf_settings";
179 private static final String BUTTON_RETRY_KEY = "button_auto_retry_key";
180 private static final String BUTTON_TTY_KEY = "button_tty_mode_key";
181 private static final String BUTTON_HAC_KEY = "button_hac_key";
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700182
183 private static final String BUTTON_GSM_UMTS_OPTIONS = "button_gsm_more_expand_key";
184 private static final String BUTTON_CDMA_OPTIONS = "button_cdma_more_expand_key";
185
186 private static final String VM_NUMBERS_SHARED_PREFERENCES_NAME = "vm_numbers";
187
Andrew Leedb2fe562014-09-03 15:40:43 -0700188 private static final String DEFAULT_OUTGOING_ACCOUNT_KEY = "default_outgoing_account";
Andrew Leece8ae2a2014-09-10 10:41:48 -0700189 private static final String PHONE_ACCOUNT_SETTINGS_KEY =
190 "phone_account_settings_preference_screen";
Andrew Leedb2fe562014-09-03 15:40:43 -0700191
Andrew Leedf14ead2014-10-17 14:22:52 -0700192 private static final String ENABLE_VIDEO_CALLING_KEY = "button_enable_video_calling";
193
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700194 private Intent mContactListIntent;
195
196 /** Event for Async voicemail change call */
197 private static final int EVENT_VOICEMAIL_CHANGED = 500;
198 private static final int EVENT_FORWARDING_CHANGED = 501;
199 private static final int EVENT_FORWARDING_GET_COMPLETED = 502;
200
Andrew Lee2170a972014-08-13 18:13:01 -0700201 private static final int MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY = 1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700202
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700203 public static final String HAC_KEY = "HACSetting";
204 public static final String HAC_VAL_ON = "ON";
205 public static final String HAC_VAL_OFF = "OFF";
206
207 /** Handle to voicemail pref */
208 private static final int VOICEMAIL_PREF_ID = 1;
209 private static final int VOICEMAIL_PROVIDER_CFG_ID = 2;
210
211 private Phone mPhone;
212
213 private AudioManager mAudioManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700214
215 private static final int VM_NOCHANGE_ERROR = 400;
216 private static final int VM_RESPONSE_ERROR = 500;
217 private static final int FW_SET_RESPONSE_ERROR = 501;
218 private static final int FW_GET_RESPONSE_ERROR = 502;
219
220
221 // dialog identifiers for voicemail
222 private static final int VOICEMAIL_DIALOG_CONFIRM = 600;
223 private static final int VOICEMAIL_FWD_SAVING_DIALOG = 601;
224 private static final int VOICEMAIL_FWD_READING_DIALOG = 602;
225 private static final int VOICEMAIL_REVERTING_DIALOG = 603;
226
227 // status message sent back from handlers
228 private static final int MSG_OK = 100;
229
230 // special statuses for voicemail controls.
231 private static final int MSG_VM_EXCEPTION = 400;
232 private static final int MSG_FW_SET_EXCEPTION = 401;
233 private static final int MSG_FW_GET_EXCEPTION = 402;
234 private static final int MSG_VM_OK = 600;
235 private static final int MSG_VM_NOCHANGE = 700;
236
237 // voicemail notification vibration string constants
238 private static final String VOICEMAIL_VIBRATION_ALWAYS = "always";
239 private static final String VOICEMAIL_VIBRATION_NEVER = "never";
240
241 private EditPhoneNumberPreference mSubMenuVoicemailSettings;
242
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700243 /** Whether dialpad plays DTMF tone or not. */
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700244 private CheckBoxPreference mButtonAutoRetry;
245 private CheckBoxPreference mButtonHAC;
246 private ListPreference mButtonDTMF;
247 private ListPreference mButtonTTY;
Andrew Leece8ae2a2014-09-10 10:41:48 -0700248 private Preference mPhoneAccountSettingsPreference;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700249 private ListPreference mVoicemailProviders;
Andrew Lee97708a42014-09-25 12:39:07 -0700250 private PreferenceScreen mVoicemailSettingsScreen;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700251 private PreferenceScreen mVoicemailSettings;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700252 private CheckBoxPreference mVoicemailNotificationVibrate;
Andrew Leedb2fe562014-09-03 15:40:43 -0700253 private AccountSelectionPreference mDefaultOutgoingAccount;
Andrew Leedf14ead2014-10-17 14:22:52 -0700254 private CheckBoxPreference mEnableVideoCalling;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700255
256 private class VoiceMailProvider {
257 public VoiceMailProvider(String name, Intent intent) {
258 this.name = name;
259 this.intent = intent;
260 }
261 public String name;
262 public Intent intent;
263 }
264
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700265 private SharedPreferences mPerProviderSavedVMNumbers;
266
267 /**
268 * Results of reading forwarding settings
269 */
270 private CallForwardInfo[] mForwardingReadResults = null;
271
272 /**
273 * Result of forwarding number change.
274 * Keys are reasons (eg. unconditional forwarding).
275 */
276 private Map<Integer, AsyncResult> mForwardingChangeResults = null;
277
278 /**
279 * Expected CF read result types.
280 * This set keeps track of the CF types for which we've issued change
281 * commands so we can tell when we've received all of the responses.
282 */
283 private Collection<Integer> mExpectedChangeResultReasons = null;
284
285 /**
286 * Result of vm number change
287 */
288 private AsyncResult mVoicemailChangeResult = null;
289
290 /**
291 * Previous VM provider setting so we can return to it in case of failure.
292 */
293 private String mPreviousVMProviderKey = null;
294
295 /**
296 * Id of the dialog being currently shown.
297 */
298 private int mCurrentDialogId = 0;
299
300 /**
301 * Flag indicating that we are invoking settings for the voicemail provider programmatically
302 * due to vm provider change.
303 */
304 private boolean mVMProviderSettingsForced = false;
305
306 /**
307 * Flag indicating that we are making changes to vm or fwd numbers
308 * due to vm provider change.
309 */
310 private boolean mChangingVMorFwdDueToProviderChange = false;
311
312 /**
313 * True if we are in the process of vm & fwd number change and vm has already been changed.
314 * This is used to decide what to do in case of rollback.
315 */
316 private boolean mVMChangeCompletedSuccessfully = false;
317
318 /**
319 * True if we had full or partial failure setting forwarding numbers and so need to roll them
320 * back.
321 */
322 private boolean mFwdChangesRequireRollback = false;
323
324 /**
325 * Id of error msg to display to user once we are done reverting the VM provider to the previous
326 * one.
327 */
328 private int mVMOrFwdSetError = 0;
329
330 /**
331 * Data about discovered voice mail settings providers.
332 * Is populated by querying which activities can handle ACTION_CONFIGURE_VOICEMAIL.
333 * They key in this map is package name + activity name.
334 * We always add an entry for the default provider with a key of empty
335 * string and intent value of null.
336 * @see #initVoiceMailProviders()
337 */
338 private final Map<String, VoiceMailProvider> mVMProvidersData =
339 new HashMap<String, VoiceMailProvider>();
340
341 /** string to hold old voicemail number as it is being updated. */
342 private String mOldVmNumber;
343
344 // New call forwarding settings and vm number we will be setting
345 // Need to save these since before we get to saving we need to asynchronously
346 // query the existing forwarding settings.
347 private CallForwardInfo[] mNewFwdSettings;
348 private String mNewVMNumber;
349
350 private boolean mForeground;
351
352 @Override
353 public void onPause() {
354 super.onPause();
355 mForeground = false;
356 }
357
358 /**
359 * We have to pull current settings from the network for all kinds of
360 * voicemail providers so we can tell whether we have to update them,
361 * so use this bit to keep track of whether we're reading settings for the
362 * default provider and should therefore save them out when done.
363 */
364 private boolean mReadingSettingsForDefaultProvider = false;
365
Tyler Gunnbaee2952014-09-10 16:01:02 -0700366 /**
367 * Used to indicate that the voicemail preference should be shown.
368 */
369 private boolean mShowVoicemailPreference = false;
370
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700371 /*
372 * Click Listeners, handle click based on objects attached to UI.
373 */
374
375 // Click listener for all toggle events
376 @Override
377 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
378 if (preference == mSubMenuVoicemailSettings) {
379 return true;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700380 } else if (preference == mButtonDTMF) {
381 return true;
382 } else if (preference == mButtonTTY) {
383 return true;
384 } else if (preference == mButtonAutoRetry) {
385 android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
386 android.provider.Settings.Global.CALL_AUTO_RETRY,
387 mButtonAutoRetry.isChecked() ? 1 : 0);
388 return true;
389 } else if (preference == mButtonHAC) {
390 int hac = mButtonHAC.isChecked() ? 1 : 0;
391 // Update HAC value in Settings database
392 Settings.System.putInt(mPhone.getContext().getContentResolver(),
393 Settings.System.HEARING_AID, hac);
394
395 // Update HAC Value in AudioManager
396 mAudioManager.setParameter(HAC_KEY, hac != 0 ? HAC_VAL_ON : HAC_VAL_OFF);
397 return true;
398 } else if (preference == mVoicemailSettings) {
Yorke Leea0f63bf2014-10-09 18:27:20 -0700399 final Dialog dialog = mVoicemailSettings.getDialog();
400 if (dialog != null) {
401 dialog.getActionBar().setDisplayHomeAsUpEnabled(false);
402 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700403 if (DBG) log("onPreferenceTreeClick: Voicemail Settings Preference is clicked.");
404 if (preference.getIntent() != null) {
405 if (DBG) {
406 log("onPreferenceTreeClick: Invoking cfg intent "
407 + preference.getIntent().getPackage());
408 }
409
410 // onActivityResult() will be responsible for resetting some of variables.
411 this.startActivityForResult(preference.getIntent(), VOICEMAIL_PROVIDER_CFG_ID);
412 return true;
413 } else {
414 if (DBG) {
415 log("onPreferenceTreeClick:"
416 + " No Intent is available. Use default behavior defined in xml.");
417 }
418
419 // There's no onActivityResult(), so we need to take care of some of variables
420 // which should be reset here.
421 mPreviousVMProviderKey = DEFAULT_VM_PROVIDER_KEY;
422 mVMProviderSettingsForced = false;
423
424 // This should let the preference use default behavior in the xml.
425 return false;
426 }
Andrew Lee97708a42014-09-25 12:39:07 -0700427 } else if (preference == mVoicemailSettingsScreen) {
Yorke Leea0f63bf2014-10-09 18:27:20 -0700428 final Dialog dialog = mVoicemailSettingsScreen.getDialog();
429 if (dialog != null) {
430 dialog.getActionBar().setDisplayHomeAsUpEnabled(false);
431 }
Andrew Lee97708a42014-09-25 12:39:07 -0700432 return false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700433 }
434 return false;
435 }
436
437 /**
438 * Implemented to support onPreferenceChangeListener to look for preference
439 * changes.
440 *
441 * @param preference is the preference to be changed
442 * @param objValue should be the value of the selection, NOT its localized
443 * display value.
444 */
445 @Override
446 public boolean onPreferenceChange(Preference preference, Object objValue) {
447 if (DBG) {
Andrew Leedf14ead2014-10-17 14:22:52 -0700448 log("onPreferenceChange(). preference: \"" + preference + "\""
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700449 + ", value: \"" + objValue + "\"");
450 }
Andrew Lee2170a972014-08-13 18:13:01 -0700451
452 if (preference == mButtonDTMF) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700453 int index = mButtonDTMF.findIndexOfValue((String) objValue);
454 Settings.System.putInt(mPhone.getContext().getContentResolver(),
455 Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, index);
456 } else if (preference == mButtonTTY) {
457 handleTTYChange(preference, objValue);
458 } else if (preference == mVoicemailProviders) {
459 final String newProviderKey = (String) objValue;
460 if (DBG) {
461 log("Voicemail Provider changes from \"" + mPreviousVMProviderKey
462 + "\" to \"" + newProviderKey + "\".");
463 }
464 // If previous provider key and the new one is same, we don't need to handle it.
465 if (mPreviousVMProviderKey.equals(newProviderKey)) {
466 if (DBG) log("No change is made toward VM provider setting.");
467 return true;
468 }
469 updateVMPreferenceWidgets(newProviderKey);
470
Andrew Leeb490d732014-10-27 15:00:41 -0700471 final VoicemailProviderSettings newProviderSettings =
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700472 loadSettingsForVoiceMailProvider(newProviderKey);
473
474 // If the user switches to a voice mail provider and we have a
475 // numbers stored for it we will automatically change the
476 // phone's
477 // voice mail and forwarding number to the stored ones.
478 // Otherwise we will bring up provider's configuration UI.
479
480 if (newProviderSettings == null) {
481 // Force the user into a configuration of the chosen provider
482 Log.w(LOG_TAG, "Saved preferences not found - invoking config");
483 mVMProviderSettingsForced = true;
484 simulatePreferenceClick(mVoicemailSettings);
485 } else {
486 if (DBG) log("Saved preferences found - switching to them");
487 // Set this flag so if we get a failure we revert to previous provider
488 mChangingVMorFwdDueToProviderChange = true;
489 saveVoiceMailAndForwardingNumber(newProviderKey, newProviderSettings);
490 }
Andrew Leedf14ead2014-10-17 14:22:52 -0700491 } else if (preference == mEnableVideoCalling) {
Andrew Lee312e8172014-10-23 17:01:36 -0700492 if (ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())) {
493 PhoneGlobals.getInstance().phoneMgr.enableVideoCalling((boolean) objValue);
494 } else {
495 AlertDialog.Builder builder = new AlertDialog.Builder(this);
496 DialogInterface.OnClickListener networkSettingsClickListener =
497 new Dialog.OnClickListener() {
498 @Override
499 public void onClick(DialogInterface dialog, int which) {
500 startActivity(new Intent(mPhone.getContext(),
501 com.android.phone.MobileNetworkSettings.class));
502 }
503 };
504 builder.setMessage(getResources().getString(
505 R.string.enable_video_calling_dialog_msg))
506 .setNeutralButton(getResources().getString(
507 R.string.enable_video_calling_dialog_settings),
508 networkSettingsClickListener)
509 .setPositiveButton(android.R.string.ok, null)
510 .show();
511 return false;
512 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700513 }
514 // always let the preference setting proceed.
515 return true;
516 }
517
518 @Override
519 public void onDialogClosed(EditPhoneNumberPreference preference, int buttonClicked) {
520 if (DBG) log("onPreferenceClick: request preference click on dialog close: " +
521 buttonClicked);
522 if (buttonClicked == DialogInterface.BUTTON_NEGATIVE) {
523 return;
524 }
525
526 if (preference == mSubMenuVoicemailSettings) {
527 handleVMBtnClickRequest();
528 }
529 }
530
531 /**
532 * Implemented for EditPhoneNumberPreference.GetDefaultNumberListener.
533 * This method set the default values for the various
534 * EditPhoneNumberPreference dialogs.
535 */
536 @Override
537 public String onGetDefaultNumber(EditPhoneNumberPreference preference) {
538 if (preference == mSubMenuVoicemailSettings) {
539 // update the voicemail number field, which takes care of the
540 // mSubMenuVoicemailSettings itself, so we should return null.
541 if (DBG) log("updating default for voicemail dialog");
542 updateVoiceNumberField();
543 return null;
544 }
545
546 String vmDisplay = mPhone.getVoiceMailNumber();
547 if (TextUtils.isEmpty(vmDisplay)) {
548 // if there is no voicemail number, we just return null to
549 // indicate no contribution.
550 return null;
551 }
552
553 // Return the voicemail number prepended with "VM: "
554 if (DBG) log("updating default for call forwarding dialogs");
555 return getString(R.string.voicemail_abbreviated) + " " + vmDisplay;
556 }
557
558
559 // override the startsubactivity call to make changes in state consistent.
560 @Override
561 public void startActivityForResult(Intent intent, int requestCode) {
562 if (requestCode == -1) {
563 // this is an intent requested from the preference framework.
564 super.startActivityForResult(intent, requestCode);
565 return;
566 }
567
568 if (DBG) log("startSubActivity: starting requested subactivity");
569 super.startActivityForResult(intent, requestCode);
570 }
571
572 private void switchToPreviousVoicemailProvider() {
573 if (DBG) log("switchToPreviousVoicemailProvider " + mPreviousVMProviderKey);
574 if (mPreviousVMProviderKey != null) {
575 if (mVMChangeCompletedSuccessfully || mFwdChangesRequireRollback) {
576 // we have to revert with carrier
577 if (DBG) {
578 log("Needs to rollback."
579 + " mVMChangeCompletedSuccessfully=" + mVMChangeCompletedSuccessfully
580 + ", mFwdChangesRequireRollback=" + mFwdChangesRequireRollback);
581 }
582
583 showDialogIfForeground(VOICEMAIL_REVERTING_DIALOG);
Andrew Leeb490d732014-10-27 15:00:41 -0700584 final VoicemailProviderSettings prevSettings =
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700585 loadSettingsForVoiceMailProvider(mPreviousVMProviderKey);
586 if (prevSettings == null) {
587 // prevSettings never becomes null since it should be already loaded!
Andrew Leeb490d732014-10-27 15:00:41 -0700588 Log.e(LOG_TAG, "VoicemailProviderSettings for the key \""
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700589 + mPreviousVMProviderKey + "\" becomes null, which is unexpected.");
590 if (DBG) {
591 Log.e(LOG_TAG,
592 "mVMChangeCompletedSuccessfully: " + mVMChangeCompletedSuccessfully
593 + ", mFwdChangesRequireRollback: " + mFwdChangesRequireRollback);
594 }
595 }
596 if (mVMChangeCompletedSuccessfully) {
Andrew Leeb490d732014-10-27 15:00:41 -0700597 mNewVMNumber = prevSettings.getVoicemailNumber();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700598 Log.i(LOG_TAG, "VM change is already completed successfully."
599 + "Have to revert VM back to " + mNewVMNumber + " again.");
600 mPhone.setVoiceMailNumber(
601 mPhone.getVoiceMailAlphaTag().toString(),
602 mNewVMNumber,
603 Message.obtain(mRevertOptionComplete, EVENT_VOICEMAIL_CHANGED));
604 }
605 if (mFwdChangesRequireRollback) {
606 Log.i(LOG_TAG, "Requested to rollback Fwd changes.");
Andrew Leeb490d732014-10-27 15:00:41 -0700607 final CallForwardInfo[] prevFwdSettings = prevSettings.getForwardingSettings();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700608 if (prevFwdSettings != null) {
609 Map<Integer, AsyncResult> results =
610 mForwardingChangeResults;
611 resetForwardingChangeState();
612 for (int i = 0; i < prevFwdSettings.length; i++) {
613 CallForwardInfo fi = prevFwdSettings[i];
614 if (DBG) log("Reverting fwd #: " + i + ": " + fi.toString());
615 // Only revert the settings for which the update
616 // succeeded
617 AsyncResult result = results.get(fi.reason);
618 if (result != null && result.exception == null) {
619 mExpectedChangeResultReasons.add(fi.reason);
620 mPhone.setCallForwardingOption(
621 (fi.status == 1 ?
622 CommandsInterface.CF_ACTION_REGISTRATION :
623 CommandsInterface.CF_ACTION_DISABLE),
624 fi.reason,
625 fi.number,
626 fi.timeSeconds,
627 mRevertOptionComplete.obtainMessage(
628 EVENT_FORWARDING_CHANGED, i, 0));
629 }
630 }
631 }
632 }
633 } else {
634 if (DBG) log("No need to revert");
635 onRevertDone();
636 }
637 }
638 }
639
640 private void onRevertDone() {
641 if (DBG) log("Flipping provider key back to " + mPreviousVMProviderKey);
642 mVoicemailProviders.setValue(mPreviousVMProviderKey);
643 updateVMPreferenceWidgets(mPreviousVMProviderKey);
644 updateVoiceNumberField();
645 if (mVMOrFwdSetError != 0) {
646 showVMDialog(mVMOrFwdSetError);
647 mVMOrFwdSetError = 0;
648 }
649 }
650
651 @Override
652 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
653 if (DBG) {
654 log("onActivityResult: requestCode: " + requestCode
655 + ", resultCode: " + resultCode
656 + ", data: " + data);
657 }
658 // there are cases where the contact picker may end up sending us more than one
659 // request. We want to ignore the request if we're not in the correct state.
660 if (requestCode == VOICEMAIL_PROVIDER_CFG_ID) {
661 boolean failure = false;
662
663 // No matter how the processing of result goes lets clear the flag
664 if (DBG) log("mVMProviderSettingsForced: " + mVMProviderSettingsForced);
665 final boolean isVMProviderSettingsForced = mVMProviderSettingsForced;
666 mVMProviderSettingsForced = false;
667
668 String vmNum = null;
669 if (resultCode != RESULT_OK) {
670 if (DBG) log("onActivityResult: vm provider cfg result not OK.");
671 failure = true;
672 } else {
673 if (data == null) {
674 if (DBG) log("onActivityResult: vm provider cfg result has no data");
675 failure = true;
676 } else {
677 if (data.getBooleanExtra(SIGNOUT_EXTRA, false)) {
678 if (DBG) log("Provider requested signout");
679 if (isVMProviderSettingsForced) {
680 if (DBG) log("Going back to previous provider on signout");
681 switchToPreviousVoicemailProvider();
682 } else {
683 final String victim = getCurrentVoicemailProviderKey();
684 if (DBG) log("Relaunching activity and ignoring " + victim);
685 Intent i = new Intent(ACTION_ADD_VOICEMAIL);
686 i.putExtra(IGNORE_PROVIDER_EXTRA, victim);
687 i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
688 this.startActivity(i);
689 }
690 return;
691 }
692 vmNum = data.getStringExtra(VM_NUMBER_EXTRA);
693 if (vmNum == null || vmNum.length() == 0) {
694 if (DBG) log("onActivityResult: vm provider cfg result has no vmnum");
695 failure = true;
696 }
697 }
698 }
699 if (failure) {
700 if (DBG) log("Failure in return from voicemail provider");
701 if (isVMProviderSettingsForced) {
702 switchToPreviousVoicemailProvider();
703 } else {
704 if (DBG) log("Not switching back the provider since this is not forced config");
705 }
706 return;
707 }
708 mChangingVMorFwdDueToProviderChange = isVMProviderSettingsForced;
709 final String fwdNum = data.getStringExtra(FWD_NUMBER_EXTRA);
710
Santos Cordonda120f42014-08-06 04:44:34 -0700711 // TODO: It would be nice to load the current network setting for this and
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700712 // send it to the provider when it's config is invoked so it can use this as default
713 final int fwdNumTime = data.getIntExtra(FWD_NUMBER_TIME_EXTRA, 20);
714
715 if (DBG) log("onActivityResult: vm provider cfg result " +
716 (fwdNum != null ? "has" : " does not have") + " forwarding number");
717 saveVoiceMailAndForwardingNumber(getCurrentVoicemailProviderKey(),
Andrew Leeb490d732014-10-27 15:00:41 -0700718 new VoicemailProviderSettings(vmNum, fwdNum, fwdNumTime));
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700719 return;
720 }
721
722 if (requestCode == VOICEMAIL_PREF_ID) {
723 if (resultCode != RESULT_OK) {
724 if (DBG) log("onActivityResult: contact picker result not OK.");
725 return;
726 }
727
728 Cursor cursor = null;
729 try {
730 cursor = getContentResolver().query(data.getData(),
731 NUM_PROJECTION, null, null, null);
732 if ((cursor == null) || (!cursor.moveToFirst())) {
733 if (DBG) log("onActivityResult: bad contact data, no results found.");
734 return;
735 }
736 mSubMenuVoicemailSettings.onPickActivityResult(cursor.getString(0));
737 return;
738 } finally {
739 if (cursor != null) {
740 cursor.close();
741 }
742 }
743 }
744
745 super.onActivityResult(requestCode, resultCode, data);
746 }
747
748 // Voicemail button logic
749 private void handleVMBtnClickRequest() {
750 // normally called on the dialog close.
751
752 // Since we're stripping the formatting out on the getPhoneNumber()
753 // call now, we won't need to do so here anymore.
754
755 saveVoiceMailAndForwardingNumber(
756 getCurrentVoicemailProviderKey(),
Andrew Leeb490d732014-10-27 15:00:41 -0700757 new VoicemailProviderSettings(mSubMenuVoicemailSettings.getPhoneNumber(),
758 VoicemailProviderSettings.NO_FORWARDING)
Tyler Gunn4d45d1c2014-09-12 22:17:53 -0700759 );
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700760 }
761
762
763 /**
764 * Wrapper around showDialog() that will silently do nothing if we're
765 * not in the foreground.
766 *
767 * This is useful here because most of the dialogs we display from
768 * this class are triggered by asynchronous events (like
769 * success/failure messages from the telephony layer) and it's
770 * possible for those events to come in even after the user has gone
771 * to a different screen.
772 */
773 // TODO: this is too brittle: it's still easy to accidentally add new
774 // code here that calls showDialog() directly (which will result in a
775 // WindowManager$BadTokenException if called after the activity has
776 // been stopped.)
777 //
778 // It would be cleaner to do the "if (mForeground)" check in one
779 // central place, maybe by using a single Handler for all asynchronous
780 // events (and have *that* discard events if we're not in the
781 // foreground.)
782 //
783 // Unfortunately it's not that simple, since we sometimes need to do
784 // actual work to handle these events whether or not we're in the
785 // foreground (see the Handler code in mSetOptionComplete for
786 // example.)
787 private void showDialogIfForeground(int id) {
788 if (mForeground) {
789 showDialog(id);
790 }
791 }
792
793 private void dismissDialogSafely(int id) {
794 try {
795 dismissDialog(id);
796 } catch (IllegalArgumentException e) {
797 // This is expected in the case where we were in the background
798 // at the time we would normally have shown the dialog, so we didn't
799 // show it.
800 }
801 }
802
Andrew Leeb490d732014-10-27 15:00:41 -0700803 private void saveVoiceMailAndForwardingNumber(
804 String key, VoicemailProviderSettings newSettings) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700805 if (DBG) log("saveVoiceMailAndForwardingNumber: " + newSettings.toString());
Andrew Leeb490d732014-10-27 15:00:41 -0700806 mNewVMNumber = newSettings.getVoicemailNumber();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700807 // empty vm number == clearing the vm number ?
808 if (mNewVMNumber == null) {
809 mNewVMNumber = "";
810 }
811
Andrew Leeb490d732014-10-27 15:00:41 -0700812 mNewFwdSettings = newSettings.getForwardingSettings();
813 if (DBG) log("newFwdNumber "
814 + String.valueOf((mNewFwdSettings != null ? mNewFwdSettings.length : 0))
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700815 + " settings");
816
817 // No fwd settings on CDMA
818 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
819 if (DBG) log("ignoring forwarding setting since this is CDMA phone");
Andrew Leeb490d732014-10-27 15:00:41 -0700820 mNewFwdSettings = VoicemailProviderSettings.NO_FORWARDING;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700821 }
822
Andrew Leee3c15212014-10-28 13:12:55 -0700823 // Throw a warning if the voicemail is the same and we did not change forwarding.
Andrew Leeb490d732014-10-27 15:00:41 -0700824 if (mNewVMNumber.equals(mOldVmNumber)
825 && mNewFwdSettings == VoicemailProviderSettings.NO_FORWARDING) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700826 showVMDialog(MSG_VM_NOCHANGE);
827 return;
828 }
829
830 maybeSaveSettingsForVoicemailProvider(key, newSettings);
831 mVMChangeCompletedSuccessfully = false;
832 mFwdChangesRequireRollback = false;
833 mVMOrFwdSetError = 0;
834 if (!key.equals(mPreviousVMProviderKey)) {
835 mReadingSettingsForDefaultProvider =
836 mPreviousVMProviderKey.equals(DEFAULT_VM_PROVIDER_KEY);
837 if (DBG) log("Reading current forwarding settings");
Andrew Leeb490d732014-10-27 15:00:41 -0700838 int numSettingsReasons = VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS.length;
839 mForwardingReadResults = new CallForwardInfo[numSettingsReasons];
840 for (int i = 0; i < mForwardingReadResults.length; i++) {
841 mPhone.getCallForwardingOption(
842 VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS[i],
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700843 mGetOptionComplete.obtainMessage(EVENT_FORWARDING_GET_COMPLETED, i, 0));
844 }
845 showDialogIfForeground(VOICEMAIL_FWD_READING_DIALOG);
846 } else {
847 saveVoiceMailAndForwardingNumberStage2();
848 }
849 }
850
851 private final Handler mGetOptionComplete = new Handler() {
852 @Override
853 public void handleMessage(Message msg) {
854 AsyncResult result = (AsyncResult) msg.obj;
855 switch (msg.what) {
856 case EVENT_FORWARDING_GET_COMPLETED:
857 handleForwardingSettingsReadResult(result, msg.arg1);
858 break;
859 }
860 }
861 };
862
863 private void handleForwardingSettingsReadResult(AsyncResult ar, int idx) {
864 if (DBG) Log.d(LOG_TAG, "handleForwardingSettingsReadResult: " + idx);
865 Throwable error = null;
866 if (ar.exception != null) {
867 if (DBG) Log.d(LOG_TAG, "FwdRead: ar.exception=" +
868 ar.exception.getMessage());
869 error = ar.exception;
870 }
871 if (ar.userObj instanceof Throwable) {
872 if (DBG) Log.d(LOG_TAG, "FwdRead: userObj=" +
873 ((Throwable)ar.userObj).getMessage());
874 error = (Throwable)ar.userObj;
875 }
876
877 // We may have already gotten an error and decided to ignore the other results.
878 if (mForwardingReadResults == null) {
879 if (DBG) Log.d(LOG_TAG, "ignoring fwd reading result: " + idx);
880 return;
881 }
882
883 // In case of error ignore other results, show an error dialog
884 if (error != null) {
885 if (DBG) Log.d(LOG_TAG, "Error discovered for fwd read : " + idx);
886 mForwardingReadResults = null;
887 dismissDialogSafely(VOICEMAIL_FWD_READING_DIALOG);
888 showVMDialog(MSG_FW_GET_EXCEPTION);
889 return;
890 }
891
892 // Get the forwarding info
893 final CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result;
894 CallForwardInfo fi = null;
895 for (int i = 0 ; i < cfInfoArray.length; i++) {
896 if ((cfInfoArray[i].serviceClass & CommandsInterface.SERVICE_CLASS_VOICE) != 0) {
897 fi = cfInfoArray[i];
898 break;
899 }
900 }
901 if (fi == null) {
902
903 // In case we go nothing it means we need this reason disabled
904 // so create a CallForwardInfo for capturing this
905 if (DBG) Log.d(LOG_TAG, "Creating default info for " + idx);
906 fi = new CallForwardInfo();
907 fi.status = 0;
Andrew Leeb490d732014-10-27 15:00:41 -0700908 fi.reason = VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS[idx];
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700909 fi.serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
910 } else {
911 // if there is not a forwarding number, ensure the entry is set to "not active."
912 if (fi.number == null || fi.number.length() == 0) {
913 fi.status = 0;
914 }
915
916 if (DBG) Log.d(LOG_TAG, "Got " + fi.toString() + " for " + idx);
917 }
918 mForwardingReadResults[idx] = fi;
919
920 // Check if we got all the results already
921 boolean done = true;
922 for (int i = 0; i < mForwardingReadResults.length; i++) {
923 if (mForwardingReadResults[i] == null) {
924 done = false;
925 break;
926 }
927 }
928 if (done) {
929 if (DBG) Log.d(LOG_TAG, "Done receiving fwd info");
930 dismissDialogSafely(VOICEMAIL_FWD_READING_DIALOG);
931 if (mReadingSettingsForDefaultProvider) {
932 maybeSaveSettingsForVoicemailProvider(DEFAULT_VM_PROVIDER_KEY,
Andrew Leeb490d732014-10-27 15:00:41 -0700933 new VoicemailProviderSettings(this.mOldVmNumber,
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700934 mForwardingReadResults));
935 mReadingSettingsForDefaultProvider = false;
936 }
937 saveVoiceMailAndForwardingNumberStage2();
938 } else {
939 if (DBG) Log.d(LOG_TAG, "Not done receiving fwd info");
940 }
941 }
942
943 private CallForwardInfo infoForReason(CallForwardInfo[] infos, int reason) {
944 CallForwardInfo result = null;
945 if (null != infos) {
946 for (CallForwardInfo info : infos) {
947 if (info.reason == reason) {
948 result = info;
949 break;
950 }
951 }
952 }
953 return result;
954 }
955
956 private boolean isUpdateRequired(CallForwardInfo oldInfo,
957 CallForwardInfo newInfo) {
958 boolean result = true;
959 if (0 == newInfo.status) {
960 // If we're disabling a type of forwarding, and it's already
961 // disabled for the account, don't make any change
962 if (oldInfo != null && oldInfo.status == 0) {
963 result = false;
964 }
965 }
966 return result;
967 }
968
969 private void resetForwardingChangeState() {
970 mForwardingChangeResults = new HashMap<Integer, AsyncResult>();
971 mExpectedChangeResultReasons = new HashSet<Integer>();
972 }
973
974 // Called after we are done saving the previous forwarding settings if
975 // we needed.
976 private void saveVoiceMailAndForwardingNumberStage2() {
977 mForwardingChangeResults = null;
978 mVoicemailChangeResult = null;
Andrew Leeb490d732014-10-27 15:00:41 -0700979 if (mNewFwdSettings != VoicemailProviderSettings.NO_FORWARDING) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700980 resetForwardingChangeState();
981 for (int i = 0; i < mNewFwdSettings.length; i++) {
982 CallForwardInfo fi = mNewFwdSettings[i];
983
984 final boolean doUpdate = isUpdateRequired(infoForReason(
985 mForwardingReadResults, fi.reason), fi);
986
987 if (doUpdate) {
988 if (DBG) log("Setting fwd #: " + i + ": " + fi.toString());
989 mExpectedChangeResultReasons.add(i);
990
991 mPhone.setCallForwardingOption(
992 fi.status == 1 ?
993 CommandsInterface.CF_ACTION_REGISTRATION :
994 CommandsInterface.CF_ACTION_DISABLE,
995 fi.reason,
996 fi.number,
997 fi.timeSeconds,
998 mSetOptionComplete.obtainMessage(
999 EVENT_FORWARDING_CHANGED, fi.reason, 0));
1000 }
1001 }
1002 showDialogIfForeground(VOICEMAIL_FWD_SAVING_DIALOG);
1003 } else {
1004 if (DBG) log("Not touching fwd #");
1005 setVMNumberWithCarrier();
1006 }
1007 }
1008
1009 private void setVMNumberWithCarrier() {
1010 if (DBG) log("save voicemail #: " + mNewVMNumber);
1011 mPhone.setVoiceMailNumber(
1012 mPhone.getVoiceMailAlphaTag().toString(),
1013 mNewVMNumber,
1014 Message.obtain(mSetOptionComplete, EVENT_VOICEMAIL_CHANGED));
1015 }
1016
1017 /**
1018 * Callback to handle option update completions
1019 */
1020 private final Handler mSetOptionComplete = new Handler() {
1021 @Override
1022 public void handleMessage(Message msg) {
1023 AsyncResult result = (AsyncResult) msg.obj;
1024 boolean done = false;
1025 switch (msg.what) {
1026 case EVENT_VOICEMAIL_CHANGED:
1027 mVoicemailChangeResult = result;
1028 mVMChangeCompletedSuccessfully = checkVMChangeSuccess() == null;
1029 if (DBG) log("VM change complete msg, VM change done = " +
1030 String.valueOf(mVMChangeCompletedSuccessfully));
1031 done = true;
1032 break;
1033 case EVENT_FORWARDING_CHANGED:
1034 mForwardingChangeResults.put(msg.arg1, result);
1035 if (result.exception != null) {
1036 Log.w(LOG_TAG, "Error in setting fwd# " + msg.arg1 + ": " +
1037 result.exception.getMessage());
1038 } else {
1039 if (DBG) log("Success in setting fwd# " + msg.arg1);
1040 }
1041 final boolean completed = checkForwardingCompleted();
1042 if (completed) {
1043 if (checkFwdChangeSuccess() == null) {
1044 if (DBG) log("Overall fwd changes completed ok, starting vm change");
1045 setVMNumberWithCarrier();
1046 } else {
1047 Log.w(LOG_TAG, "Overall fwd changes completed in failure. " +
1048 "Check if we need to try rollback for some settings.");
1049 mFwdChangesRequireRollback = false;
1050 Iterator<Map.Entry<Integer,AsyncResult>> it =
1051 mForwardingChangeResults.entrySet().iterator();
1052 while (it.hasNext()) {
1053 Map.Entry<Integer,AsyncResult> entry = it.next();
1054 if (entry.getValue().exception == null) {
1055 // If at least one succeeded we have to revert
1056 Log.i(LOG_TAG, "Rollback will be required");
1057 mFwdChangesRequireRollback = true;
1058 break;
1059 }
1060 }
1061 if (!mFwdChangesRequireRollback) {
1062 Log.i(LOG_TAG, "No rollback needed.");
1063 }
1064 done = true;
1065 }
1066 }
1067 break;
1068 default:
1069 // TODO: should never reach this, may want to throw exception
1070 }
1071 if (done) {
1072 if (DBG) log("All VM provider related changes done");
1073 if (mForwardingChangeResults != null) {
1074 dismissDialogSafely(VOICEMAIL_FWD_SAVING_DIALOG);
1075 }
1076 handleSetVMOrFwdMessage();
1077 }
1078 }
1079 };
1080
1081 /**
1082 * Callback to handle option revert completions
1083 */
1084 private final Handler mRevertOptionComplete = new Handler() {
1085 @Override
1086 public void handleMessage(Message msg) {
1087 AsyncResult result = (AsyncResult) msg.obj;
1088 switch (msg.what) {
1089 case EVENT_VOICEMAIL_CHANGED:
1090 mVoicemailChangeResult = result;
1091 if (DBG) log("VM revert complete msg");
1092 break;
1093 case EVENT_FORWARDING_CHANGED:
1094 mForwardingChangeResults.put(msg.arg1, result);
1095 if (result.exception != null) {
1096 if (DBG) log("Error in reverting fwd# " + msg.arg1 + ": " +
1097 result.exception.getMessage());
1098 } else {
1099 if (DBG) log("Success in reverting fwd# " + msg.arg1);
1100 }
1101 if (DBG) log("FWD revert complete msg ");
1102 break;
1103 default:
1104 // TODO: should never reach this, may want to throw exception
1105 }
1106 final boolean done =
1107 (!mVMChangeCompletedSuccessfully || mVoicemailChangeResult != null) &&
1108 (!mFwdChangesRequireRollback || checkForwardingCompleted());
1109 if (done) {
1110 if (DBG) log("All VM reverts done");
1111 dismissDialogSafely(VOICEMAIL_REVERTING_DIALOG);
1112 onRevertDone();
1113 }
1114 }
1115 };
1116
1117 /**
1118 * @return true if forwarding change has completed
1119 */
1120 private boolean checkForwardingCompleted() {
1121 boolean result;
1122 if (mForwardingChangeResults == null) {
1123 result = true;
1124 } else {
1125 // return true iff there is a change result for every reason for
1126 // which we expected a result
1127 result = true;
1128 for (Integer reason : mExpectedChangeResultReasons) {
1129 if (mForwardingChangeResults.get(reason) == null) {
1130 result = false;
1131 break;
1132 }
1133 }
1134 }
1135 return result;
1136 }
1137 /**
1138 * @return error string or null if successful
1139 */
1140 private String checkFwdChangeSuccess() {
1141 String result = null;
1142 Iterator<Map.Entry<Integer,AsyncResult>> it =
1143 mForwardingChangeResults.entrySet().iterator();
1144 while (it.hasNext()) {
1145 Map.Entry<Integer,AsyncResult> entry = it.next();
1146 Throwable exception = entry.getValue().exception;
1147 if (exception != null) {
1148 result = exception.getMessage();
1149 if (result == null) {
1150 result = "";
1151 }
1152 break;
1153 }
1154 }
1155 return result;
1156 }
1157
1158 /**
1159 * @return error string or null if successful
1160 */
1161 private String checkVMChangeSuccess() {
1162 if (mVoicemailChangeResult.exception != null) {
1163 final String msg = mVoicemailChangeResult.exception.getMessage();
1164 if (msg == null) {
1165 return "";
1166 }
1167 return msg;
1168 }
1169 return null;
1170 }
1171
1172 private void handleSetVMOrFwdMessage() {
1173 if (DBG) {
1174 log("handleSetVMMessage: set VM request complete");
1175 }
1176 boolean success = true;
1177 boolean fwdFailure = false;
1178 String exceptionMessage = "";
1179 if (mForwardingChangeResults != null) {
1180 exceptionMessage = checkFwdChangeSuccess();
1181 if (exceptionMessage != null) {
1182 success = false;
1183 fwdFailure = true;
1184 }
1185 }
1186 if (success) {
1187 exceptionMessage = checkVMChangeSuccess();
1188 if (exceptionMessage != null) {
1189 success = false;
1190 }
1191 }
1192 if (success) {
1193 if (DBG) log("change VM success!");
1194 handleVMAndFwdSetSuccess(MSG_VM_OK);
1195 } else {
1196 if (fwdFailure) {
1197 Log.w(LOG_TAG, "Failed to change fowarding setting. Reason: " + exceptionMessage);
1198 handleVMOrFwdSetError(MSG_FW_SET_EXCEPTION);
1199 } else {
1200 Log.w(LOG_TAG, "Failed to change voicemail. Reason: " + exceptionMessage);
1201 handleVMOrFwdSetError(MSG_VM_EXCEPTION);
1202 }
1203 }
1204 }
1205
1206 /**
1207 * Called when Voicemail Provider or its forwarding settings failed. Rolls back partly made
1208 * changes to those settings and show "failure" dialog.
1209 *
1210 * @param msgId Message ID used for the specific error case. {@link #MSG_FW_SET_EXCEPTION} or
1211 * {@link #MSG_VM_EXCEPTION}
1212 */
1213 private void handleVMOrFwdSetError(int msgId) {
1214 if (mChangingVMorFwdDueToProviderChange) {
1215 mVMOrFwdSetError = msgId;
1216 mChangingVMorFwdDueToProviderChange = false;
1217 switchToPreviousVoicemailProvider();
1218 return;
1219 }
1220 mChangingVMorFwdDueToProviderChange = false;
1221 showVMDialog(msgId);
1222 updateVoiceNumberField();
1223 }
1224
1225 /**
1226 * Called when Voicemail Provider and its forwarding settings were successfully finished.
1227 * This updates a bunch of variables and show "success" dialog.
1228 */
1229 private void handleVMAndFwdSetSuccess(int msg) {
1230 if (DBG) {
1231 log("handleVMAndFwdSetSuccess(). current voicemail provider key: "
1232 + getCurrentVoicemailProviderKey());
1233 }
1234 mPreviousVMProviderKey = getCurrentVoicemailProviderKey();
1235 mChangingVMorFwdDueToProviderChange = false;
1236 showVMDialog(msg);
1237 updateVoiceNumberField();
1238 }
1239
1240 /**
1241 * Update the voicemail number from what we've recorded on the sim.
1242 */
1243 private void updateVoiceNumberField() {
1244 if (DBG) {
1245 log("updateVoiceNumberField(). mSubMenuVoicemailSettings=" + mSubMenuVoicemailSettings);
1246 }
1247 if (mSubMenuVoicemailSettings == null) {
1248 return;
1249 }
1250
1251 mOldVmNumber = mPhone.getVoiceMailNumber();
1252 if (mOldVmNumber == null) {
1253 mOldVmNumber = "";
1254 }
1255 mSubMenuVoicemailSettings.setPhoneNumber(mOldVmNumber);
1256 final String summary = (mOldVmNumber.length() > 0) ? mOldVmNumber :
1257 getString(R.string.voicemail_number_not_set);
1258 mSubMenuVoicemailSettings.setSummary(summary);
1259 }
1260
1261 /*
1262 * Helper Methods for Activity class.
1263 * The initial query commands are split into two pieces now
1264 * for individual expansion. This combined with the ability
1265 * to cancel queries allows for a much better user experience,
1266 * and also ensures that the user only waits to update the
1267 * data that is relevant.
1268 */
1269
1270 @Override
1271 protected void onPrepareDialog(int id, Dialog dialog) {
1272 super.onPrepareDialog(id, dialog);
1273 mCurrentDialogId = id;
1274 }
1275
1276 // dialog creation method, called by showDialog()
1277 @Override
1278 protected Dialog onCreateDialog(int id) {
1279 if ((id == VM_RESPONSE_ERROR) || (id == VM_NOCHANGE_ERROR) ||
1280 (id == FW_SET_RESPONSE_ERROR) || (id == FW_GET_RESPONSE_ERROR) ||
1281 (id == VOICEMAIL_DIALOG_CONFIRM)) {
1282
1283 AlertDialog.Builder b = new AlertDialog.Builder(this);
1284
1285 int msgId;
1286 int titleId = R.string.error_updating_title;
1287 switch (id) {
1288 case VOICEMAIL_DIALOG_CONFIRM:
1289 msgId = R.string.vm_changed;
1290 titleId = R.string.voicemail;
1291 // Set Button 2
1292 b.setNegativeButton(R.string.close_dialog, this);
1293 break;
1294 case VM_NOCHANGE_ERROR:
1295 // even though this is technically an error,
1296 // keep the title friendly.
1297 msgId = R.string.no_change;
1298 titleId = R.string.voicemail;
1299 // Set Button 2
1300 b.setNegativeButton(R.string.close_dialog, this);
1301 break;
1302 case VM_RESPONSE_ERROR:
1303 msgId = R.string.vm_change_failed;
1304 // Set Button 1
1305 b.setPositiveButton(R.string.close_dialog, this);
1306 break;
1307 case FW_SET_RESPONSE_ERROR:
1308 msgId = R.string.fw_change_failed;
1309 // Set Button 1
1310 b.setPositiveButton(R.string.close_dialog, this);
1311 break;
1312 case FW_GET_RESPONSE_ERROR:
1313 msgId = R.string.fw_get_in_vm_failed;
1314 b.setPositiveButton(R.string.alert_dialog_yes, this);
1315 b.setNegativeButton(R.string.alert_dialog_no, this);
1316 break;
1317 default:
1318 msgId = R.string.exception_error;
1319 // Set Button 3, tells the activity that the error is
1320 // not recoverable on dialog exit.
1321 b.setNeutralButton(R.string.close_dialog, this);
1322 break;
1323 }
1324
1325 b.setTitle(getText(titleId));
1326 String message = getText(msgId).toString();
1327 b.setMessage(message);
1328 b.setCancelable(false);
1329 AlertDialog dialog = b.create();
1330
1331 // make the dialog more obvious by bluring the background.
1332 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1333
1334 return dialog;
1335 } else if (id == VOICEMAIL_FWD_SAVING_DIALOG || id == VOICEMAIL_FWD_READING_DIALOG ||
1336 id == VOICEMAIL_REVERTING_DIALOG) {
1337 ProgressDialog dialog = new ProgressDialog(this);
1338 dialog.setTitle(getText(R.string.updating_title));
1339 dialog.setIndeterminate(true);
1340 dialog.setCancelable(false);
1341 dialog.setMessage(getText(
1342 id == VOICEMAIL_FWD_SAVING_DIALOG ? R.string.updating_settings :
1343 (id == VOICEMAIL_REVERTING_DIALOG ? R.string.reverting_settings :
1344 R.string.reading_settings)));
1345 return dialog;
1346 }
1347
1348
1349 return null;
1350 }
1351
1352 // This is a method implemented for DialogInterface.OnClickListener.
1353 // Used with the error dialog to close the app, voicemail dialog to just dismiss.
1354 // Close button is mapped to BUTTON_POSITIVE for the errors that close the activity,
1355 // while those that are mapped to BUTTON_NEUTRAL only move the preference focus.
1356 public void onClick(DialogInterface dialog, int which) {
1357 dialog.dismiss();
1358 switch (which){
1359 case DialogInterface.BUTTON_NEUTRAL:
1360 if (DBG) log("Neutral button");
1361 break;
1362 case DialogInterface.BUTTON_NEGATIVE:
1363 if (DBG) log("Negative button");
1364 if (mCurrentDialogId == FW_GET_RESPONSE_ERROR) {
1365 // We failed to get current forwarding settings and the user
1366 // does not wish to continue.
1367 switchToPreviousVoicemailProvider();
1368 }
1369 break;
1370 case DialogInterface.BUTTON_POSITIVE:
1371 if (DBG) log("Positive button");
1372 if (mCurrentDialogId == FW_GET_RESPONSE_ERROR) {
1373 // We failed to get current forwarding settings but the user
1374 // wishes to continue changing settings to the new vm provider
1375 saveVoiceMailAndForwardingNumberStage2();
1376 } else {
1377 finish();
1378 }
1379 return;
1380 default:
1381 // just let the dialog close and go back to the input
1382 }
1383 // In all dialogs, all buttons except BUTTON_POSITIVE lead to the end of user interaction
1384 // with settings UI. If we were called to explicitly configure voice mail then
1385 // we finish the settings activity here to come back to whatever the user was doing.
1386 if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) {
1387 finish();
1388 }
1389 }
1390
1391 // set the app state with optional status.
1392 private void showVMDialog(int msgStatus) {
1393 switch (msgStatus) {
1394 // It's a bit worrisome to punt in the error cases here when we're
1395 // not in the foreground; maybe toast instead?
1396 case MSG_VM_EXCEPTION:
1397 showDialogIfForeground(VM_RESPONSE_ERROR);
1398 break;
1399 case MSG_FW_SET_EXCEPTION:
1400 showDialogIfForeground(FW_SET_RESPONSE_ERROR);
1401 break;
1402 case MSG_FW_GET_EXCEPTION:
1403 showDialogIfForeground(FW_GET_RESPONSE_ERROR);
1404 break;
1405 case MSG_VM_NOCHANGE:
1406 showDialogIfForeground(VM_NOCHANGE_ERROR);
1407 break;
1408 case MSG_VM_OK:
1409 showDialogIfForeground(VOICEMAIL_DIALOG_CONFIRM);
1410 break;
1411 case MSG_OK:
1412 default:
1413 // This should never happen.
1414 }
1415 }
1416
1417 /*
1418 * Activity class methods
1419 */
1420
1421 @Override
1422 protected void onCreate(Bundle icicle) {
1423 super.onCreate(icicle);
1424 if (DBG) log("onCreate(). Intent: " + getIntent());
1425 mPhone = PhoneGlobals.getPhone();
Tyler Gunnbaee2952014-09-10 16:01:02 -07001426 mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1427
1428 // create intent to bring up contact list
1429 mContactListIntent = new Intent(Intent.ACTION_GET_CONTENT);
1430 mContactListIntent.setType(android.provider.Contacts.Phones.CONTENT_ITEM_TYPE);
1431
Tyler Gunnbaee2952014-09-10 16:01:02 -07001432 // Show the voicemail preference in onResume if the calling intent specifies the
1433 // ACTION_ADD_VOICEMAIL action.
1434 mShowVoicemailPreference = (icicle == null) &&
1435 getIntent().getAction().equals(ACTION_ADD_VOICEMAIL);
1436 }
1437
1438 private void initPhoneAccountPreferences() {
Andrew Leece8ae2a2014-09-10 10:41:48 -07001439 mPhoneAccountSettingsPreference = findPreference(PHONE_ACCOUNT_SETTINGS_KEY);
Tyler Gunnbaee2952014-09-10 16:01:02 -07001440
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001441 TelecomManager telecomManager = TelecomManager.from(this);
Andrew Lee93c345f2014-10-27 15:25:07 -07001442 TelephonyManager telephonyManager =
1443 (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Tyler Gunnbaee2952014-09-10 16:01:02 -07001444
Andrew Lee93c345f2014-10-27 15:25:07 -07001445 if ((telecomManager.getSimCallManagers().isEmpty() && !SipUtil.isVoipSupported(this))
1446 || telephonyManager.getPhoneCount() > 1) {
Andrew Leece8ae2a2014-09-10 10:41:48 -07001447 getPreferenceScreen().removePreference(mPhoneAccountSettingsPreference);
Tyler Gunnbaee2952014-09-10 16:01:02 -07001448 }
1449 }
1450
1451 private boolean canLaunchIntent(Intent intent) {
1452 PackageManager pm = getPackageManager();
1453 return pm.resolveActivity(intent, PackageManager.GET_ACTIVITIES) != null;
1454 }
1455
Tyler Gunnbaee2952014-09-10 16:01:02 -07001456 @Override
1457 protected void onResume() {
1458 super.onResume();
1459 mForeground = true;
1460
1461 PreferenceScreen preferenceScreen = getPreferenceScreen();
1462 if (preferenceScreen != null) {
1463 preferenceScreen.removeAll();
1464 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001465
1466 addPreferencesFromResource(R.xml.call_feature_setting);
Andrew Leedb2fe562014-09-03 15:40:43 -07001467 initPhoneAccountPreferences();
1468
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001469 // get buttons
1470 PreferenceScreen prefSet = getPreferenceScreen();
Andrew Lee64a7d792014-10-15 17:38:38 -07001471 mSubMenuVoicemailSettings = (EditPhoneNumberPreference) findPreference(BUTTON_VOICEMAIL_KEY);
1472 mSubMenuVoicemailSettings.setParentActivity(this, VOICEMAIL_PREF_ID, this);
1473 mSubMenuVoicemailSettings.setDialogOnClosedListener(this);
1474 mSubMenuVoicemailSettings.setDialogTitle(R.string.voicemail_settings_number_label);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001475
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001476 mButtonDTMF = (ListPreference) findPreference(BUTTON_DTMF_KEY);
1477 mButtonAutoRetry = (CheckBoxPreference) findPreference(BUTTON_RETRY_KEY);
1478 mButtonHAC = (CheckBoxPreference) findPreference(BUTTON_HAC_KEY);
1479 mButtonTTY = (ListPreference) findPreference(BUTTON_TTY_KEY);
1480 mVoicemailProviders = (ListPreference) findPreference(BUTTON_VOICEMAIL_PROVIDER_KEY);
Andrew Lee312e8172014-10-23 17:01:36 -07001481 mEnableVideoCalling = (CheckBoxPreference) findPreference(ENABLE_VIDEO_CALLING_KEY);
Andrew Lee2170a972014-08-13 18:13:01 -07001482
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001483 if (mVoicemailProviders != null) {
1484 mVoicemailProviders.setOnPreferenceChangeListener(this);
Andrew Lee97708a42014-09-25 12:39:07 -07001485 mVoicemailSettingsScreen =
1486 (PreferenceScreen) findPreference(VOICEMAIL_SETTING_SCREEN_PREF_KEY);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001487 mVoicemailSettings = (PreferenceScreen)findPreference(BUTTON_VOICEMAIL_SETTING_KEY);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001488 mVoicemailNotificationVibrate =
1489 (CheckBoxPreference) findPreference(BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY);
1490 initVoiceMailProviders();
1491 }
1492
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001493
Andrew Lee64a7d792014-10-15 17:38:38 -07001494 if (getResources().getBoolean(R.bool.dtmf_type_enabled)) {
1495 mButtonDTMF.setOnPreferenceChangeListener(this);
1496 int dtmf = Settings.System.getInt(getContentResolver(),
1497 Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, Constants.DTMF_TONE_TYPE_NORMAL);
1498 mButtonDTMF.setValueIndex(dtmf);
1499 } else {
1500 prefSet.removePreference(mButtonDTMF);
1501 mButtonDTMF = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001502 }
1503
Andrew Lee64a7d792014-10-15 17:38:38 -07001504 if (getResources().getBoolean(R.bool.auto_retry_enabled)) {
1505 mButtonAutoRetry.setOnPreferenceChangeListener(this);
1506 int autoretry = Settings.Global.getInt(
1507 getContentResolver(), Settings.Global.CALL_AUTO_RETRY, 0);
1508 mButtonAutoRetry.setChecked(autoretry != 0);
1509 } else {
1510 prefSet.removePreference(mButtonAutoRetry);
1511 mButtonAutoRetry = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001512 }
1513
Andrew Lee64a7d792014-10-15 17:38:38 -07001514 if (getResources().getBoolean(R.bool.hac_enabled)) {
1515 mButtonHAC.setOnPreferenceChangeListener(this);
1516 int hac = Settings.System.getInt(getContentResolver(), Settings.System.HEARING_AID, 0);
1517 mButtonHAC.setChecked(hac != 0);
1518 } else {
1519 prefSet.removePreference(mButtonHAC);
1520 mButtonHAC = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001521 }
1522
Andrew Lee64a7d792014-10-15 17:38:38 -07001523 TelecomManager telecomManager = TelecomManager.from(this);
1524 if (telecomManager != null && telecomManager.isTtySupported()) {
1525 mButtonTTY.setOnPreferenceChangeListener(this);
1526 int settingsTtyMode = Settings.Secure.getInt(getContentResolver(),
1527 Settings.Secure.PREFERRED_TTY_MODE,
1528 TelecomManager.TTY_MODE_OFF);
1529 mButtonTTY.setValue(Integer.toString(settingsTtyMode));
1530 updatePreferredTtyModeSummary(settingsTtyMode);
1531 } else {
1532 prefSet.removePreference(mButtonTTY);
1533 mButtonTTY = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001534 }
1535
1536 if (!getResources().getBoolean(R.bool.world_phone)) {
1537 Preference options = prefSet.findPreference(BUTTON_CDMA_OPTIONS);
Andrew Lee2170a972014-08-13 18:13:01 -07001538 if (options != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001539 prefSet.removePreference(options);
Andrew Lee2170a972014-08-13 18:13:01 -07001540 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001541 options = prefSet.findPreference(BUTTON_GSM_UMTS_OPTIONS);
Andrew Lee2170a972014-08-13 18:13:01 -07001542 if (options != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001543 prefSet.removePreference(options);
Andrew Lee2170a972014-08-13 18:13:01 -07001544 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001545
1546 int phoneType = mPhone.getPhoneType();
1547 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
1548 Preference fdnButton = prefSet.findPreference(BUTTON_FDN_KEY);
Andrew Lee2170a972014-08-13 18:13:01 -07001549 if (fdnButton != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001550 prefSet.removePreference(fdnButton);
Andrew Lee2170a972014-08-13 18:13:01 -07001551 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001552 if (!getResources().getBoolean(R.bool.config_voice_privacy_disable)) {
1553 addPreferencesFromResource(R.xml.cdma_call_privacy);
1554 }
1555 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
Andrew Lee2170a972014-08-13 18:13:01 -07001556 if (getResources().getBoolean(R.bool.config_additional_call_setting)) {
Etan Cohen0ca1c802014-07-07 15:35:48 -07001557 addPreferencesFromResource(R.xml.gsm_umts_call_options);
1558 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001559 } else {
1560 throw new IllegalStateException("Unexpected phone type: " + phoneType);
1561 }
1562 }
1563
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001564 // check the intent that started this activity and pop up the voicemail
1565 // dialog if we've been asked to.
1566 // If we have at least one non default VM provider registered then bring up
1567 // the selection for the VM provider, otherwise bring up a VM number dialog.
1568 // We only bring up the dialog the first time we are called (not after orientation change)
Tyler Gunnbaee2952014-09-10 16:01:02 -07001569 if (mShowVoicemailPreference && mVoicemailProviders != null) {
1570 if (DBG) {
1571 log("ACTION_ADD_VOICEMAIL Intent is thrown. current VM data size: "
1572 + mVMProvidersData.size());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001573 }
Tyler Gunnbaee2952014-09-10 16:01:02 -07001574 if (mVMProvidersData.size() > 1) {
1575 simulatePreferenceClick(mVoicemailProviders);
1576 } else {
1577 onPreferenceChange(mVoicemailProviders, DEFAULT_VM_PROVIDER_KEY);
1578 mVoicemailProviders.setValue(DEFAULT_VM_PROVIDER_KEY);
1579 }
1580 mShowVoicemailPreference = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001581 }
Tyler Gunnbaee2952014-09-10 16:01:02 -07001582
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001583 updateVoiceNumberField();
1584 mVMProviderSettingsForced = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001585
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001586 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
1587 mPhone.getContext());
1588 if (migrateVoicemailVibrationSettingsIfNeeded(prefs)) {
1589 mVoicemailNotificationVibrate.setChecked(prefs.getBoolean(
1590 BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY, false));
1591 }
1592
Andrew Lee312e8172014-10-23 17:01:36 -07001593 if (ImsManager.isVtEnabledByPlatform(mPhone.getContext()) && ENABLE_VT_FLAG) {
1594 boolean currentValue =
1595 ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())
1596 ? PhoneGlobals.getInstance().phoneMgr.isVideoCallingEnabled() : false;
1597 mEnableVideoCalling.setChecked(currentValue);
Andrew Lee77527ac2014-10-21 16:57:39 -07001598 mEnableVideoCalling.setOnPreferenceChangeListener(this);
1599 } else {
1600 prefSet.removePreference(mEnableVideoCalling);
1601 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001602 }
1603
1604 // Migrate settings from BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_WHEN_KEY to
1605 // BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY, if the latter does not exist.
1606 // Returns true if migration was performed.
1607 public static boolean migrateVoicemailVibrationSettingsIfNeeded(SharedPreferences prefs) {
1608 if (!prefs.contains(BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY)) {
1609 String vibrateWhen = prefs.getString(
1610 BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_WHEN_KEY, VOICEMAIL_VIBRATION_NEVER);
1611 // If vibrateWhen is always, then voicemailVibrate should be True.
1612 // otherwise if vibrateWhen is "only in silent mode", or "never", then
1613 // voicemailVibrate = False.
1614 boolean voicemailVibrate = vibrateWhen.equals(VOICEMAIL_VIBRATION_ALWAYS);
1615 final SharedPreferences.Editor editor = prefs.edit();
1616 editor.putBoolean(BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY, voicemailVibrate);
1617 editor.commit();
1618 return true;
1619 }
1620 return false;
1621 }
1622
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001623 private boolean isAirplaneModeOn() {
1624 return Settings.System.getInt(getContentResolver(),
1625 Settings.System.AIRPLANE_MODE_ON, 0) != 0;
1626 }
1627
1628 private void handleTTYChange(Preference preference, Object objValue) {
1629 int buttonTtyMode;
1630 buttonTtyMode = Integer.valueOf((String) objValue).intValue();
1631 int settingsTtyMode = android.provider.Settings.Secure.getInt(
1632 getContentResolver(),
Sailesh Nepalbf900542014-07-15 16:18:32 -07001633 android.provider.Settings.Secure.PREFERRED_TTY_MODE,
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001634 TelecomManager.TTY_MODE_OFF);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001635 if (DBG) log("handleTTYChange: requesting set TTY mode enable (TTY) to" +
1636 Integer.toString(buttonTtyMode));
1637
1638 if (buttonTtyMode != settingsTtyMode) {
1639 switch(buttonTtyMode) {
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001640 case TelecomManager.TTY_MODE_OFF:
1641 case TelecomManager.TTY_MODE_FULL:
1642 case TelecomManager.TTY_MODE_HCO:
1643 case TelecomManager.TTY_MODE_VCO:
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001644 android.provider.Settings.Secure.putInt(getContentResolver(),
1645 android.provider.Settings.Secure.PREFERRED_TTY_MODE, buttonTtyMode);
1646 break;
1647 default:
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001648 buttonTtyMode = TelecomManager.TTY_MODE_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001649 }
1650
1651 mButtonTTY.setValue(Integer.toString(buttonTtyMode));
1652 updatePreferredTtyModeSummary(buttonTtyMode);
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001653 Intent ttyModeChanged = new Intent(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
1654 ttyModeChanged.putExtra(TelecomManager.EXTRA_TTY_PREFERRED_MODE, buttonTtyMode);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001655 sendBroadcastAsUser(ttyModeChanged, UserHandle.ALL);
1656 }
1657 }
1658
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001659 private void updatePreferredTtyModeSummary(int TtyMode) {
1660 String [] txts = getResources().getStringArray(R.array.tty_mode_entries);
1661 switch(TtyMode) {
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001662 case TelecomManager.TTY_MODE_OFF:
1663 case TelecomManager.TTY_MODE_HCO:
1664 case TelecomManager.TTY_MODE_VCO:
1665 case TelecomManager.TTY_MODE_FULL:
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001666 mButtonTTY.setSummary(txts[TtyMode]);
1667 break;
1668 default:
1669 mButtonTTY.setEnabled(false);
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001670 mButtonTTY.setSummary(txts[TelecomManager.TTY_MODE_OFF]);
Sailesh Nepalbf900542014-07-15 16:18:32 -07001671 break;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001672 }
1673 }
1674
1675 private static void log(String msg) {
1676 Log.d(LOG_TAG, msg);
1677 }
1678
1679 /**
1680 * Updates the look of the VM preference widgets based on current VM provider settings.
1681 * Note that the provider name is loaded form the found activity via loadLabel in
1682 * {@link #initVoiceMailProviders()} in order for it to be localizable.
1683 */
1684 private void updateVMPreferenceWidgets(String currentProviderSetting) {
1685 final String key = currentProviderSetting;
1686 final VoiceMailProvider provider = mVMProvidersData.get(key);
1687
1688 /* This is the case when we are coming up on a freshly wiped phone and there is no
1689 persisted value for the list preference mVoicemailProviders.
1690 In this case we want to show the UI asking the user to select a voicemail provider as
1691 opposed to silently falling back to default one. */
1692 if (provider == null) {
1693 if (DBG) {
1694 log("updateVMPreferenceWidget: provider for the key \"" + key + "\" is null.");
1695 }
1696 mVoicemailProviders.setSummary(getString(R.string.sum_voicemail_choose_provider));
1697 mVoicemailSettings.setEnabled(false);
1698 mVoicemailSettings.setIntent(null);
1699
1700 mVoicemailNotificationVibrate.setEnabled(false);
1701 } else {
1702 if (DBG) {
1703 log("updateVMPreferenceWidget: provider for the key \"" + key + "\".."
1704 + "name: " + provider.name
1705 + ", intent: " + provider.intent);
1706 }
1707 final String providerName = provider.name;
1708 mVoicemailProviders.setSummary(providerName);
1709 mVoicemailSettings.setEnabled(true);
1710 mVoicemailSettings.setIntent(provider.intent);
1711
1712 mVoicemailNotificationVibrate.setEnabled(true);
1713 }
1714 }
1715
1716 /**
1717 * Enumerates existing VM providers and puts their data into the list and populates
1718 * the preference list objects with their names.
1719 * In case we are called with ACTION_ADD_VOICEMAIL intent the intent may have
1720 * an extra string called IGNORE_PROVIDER_EXTRA with "package.activityName" of the provider
1721 * which should be hidden when we bring up the list of possible VM providers to choose.
1722 */
1723 private void initVoiceMailProviders() {
1724 if (DBG) log("initVoiceMailProviders()");
1725 mPerProviderSavedVMNumbers =
1726 this.getApplicationContext().getSharedPreferences(
1727 VM_NUMBERS_SHARED_PREFERENCES_NAME, MODE_PRIVATE);
1728
1729 String providerToIgnore = null;
1730 if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) {
1731 if (getIntent().hasExtra(IGNORE_PROVIDER_EXTRA)) {
1732 providerToIgnore = getIntent().getStringExtra(IGNORE_PROVIDER_EXTRA);
1733 }
1734 if (DBG) log("Found ACTION_ADD_VOICEMAIL. providerToIgnore=" + providerToIgnore);
1735 if (providerToIgnore != null) {
1736 // IGNORE_PROVIDER_EXTRA implies we want to remove the choice from the list.
1737 deleteSettingsForVoicemailProvider(providerToIgnore);
1738 }
1739 }
1740
1741 mVMProvidersData.clear();
1742
1743 // Stick the default element which is always there
1744 final String myCarrier = getString(R.string.voicemail_default);
1745 mVMProvidersData.put(DEFAULT_VM_PROVIDER_KEY, new VoiceMailProvider(myCarrier, null));
1746
1747 // Enumerate providers
1748 PackageManager pm = getPackageManager();
1749 Intent intent = new Intent();
1750 intent.setAction(ACTION_CONFIGURE_VOICEMAIL);
1751 List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
1752 int len = resolveInfos.size() + 1; // +1 for the default choice we will insert.
1753
1754 // Go through the list of discovered providers populating the data map
1755 // skip the provider we were instructed to ignore if there was one
1756 for (int i = 0; i < resolveInfos.size(); i++) {
1757 final ResolveInfo ri= resolveInfos.get(i);
1758 final ActivityInfo currentActivityInfo = ri.activityInfo;
1759 final String key = makeKeyForActivity(currentActivityInfo);
1760 if (key.equals(providerToIgnore)) {
1761 if (DBG) log("Ignoring key: " + key);
1762 len--;
1763 continue;
1764 }
1765 if (DBG) log("Loading key: " + key);
1766 final String nameForDisplay = ri.loadLabel(pm).toString();
1767 Intent providerIntent = new Intent();
1768 providerIntent.setAction(ACTION_CONFIGURE_VOICEMAIL);
1769 providerIntent.setClassName(currentActivityInfo.packageName,
1770 currentActivityInfo.name);
1771 if (DBG) {
1772 log("Store loaded VoiceMailProvider. key: " + key
1773 + " -> name: " + nameForDisplay + ", intent: " + providerIntent);
1774 }
1775 mVMProvidersData.put(
1776 key,
1777 new VoiceMailProvider(nameForDisplay, providerIntent));
1778
1779 }
1780
1781 // Now we know which providers to display - create entries and values array for
1782 // the list preference
1783 String [] entries = new String [len];
1784 String [] values = new String [len];
1785 entries[0] = myCarrier;
1786 values[0] = DEFAULT_VM_PROVIDER_KEY;
1787 int entryIdx = 1;
1788 for (int i = 0; i < resolveInfos.size(); i++) {
1789 final String key = makeKeyForActivity(resolveInfos.get(i).activityInfo);
1790 if (!mVMProvidersData.containsKey(key)) {
1791 continue;
1792 }
1793 entries[entryIdx] = mVMProvidersData.get(key).name;
1794 values[entryIdx] = key;
1795 entryIdx++;
1796 }
1797
1798 // ListPreference is now updated.
1799 mVoicemailProviders.setEntries(entries);
1800 mVoicemailProviders.setEntryValues(values);
1801
1802 // Remember the current Voicemail Provider key as a "previous" key. This will be used
1803 // when we fail to update Voicemail Provider, which requires rollback.
1804 // We will update this when the VM Provider setting is successfully updated.
1805 mPreviousVMProviderKey = getCurrentVoicemailProviderKey();
1806 if (DBG) log("Set up the first mPreviousVMProviderKey: " + mPreviousVMProviderKey);
1807
1808 // Finally update the preference texts.
1809 updateVMPreferenceWidgets(mPreviousVMProviderKey);
1810 }
1811
1812 private String makeKeyForActivity(ActivityInfo ai) {
1813 return ai.name;
1814 }
1815
1816 /**
1817 * Simulates user clicking on a passed preference.
1818 * Usually needed when the preference is a dialog preference and we want to invoke
1819 * a dialog for this preference programmatically.
Santos Cordonda120f42014-08-06 04:44:34 -07001820 * TODO: figure out if there is a cleaner way to cause preference dlg to come up
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001821 */
1822 private void simulatePreferenceClick(Preference preference) {
1823 // Go through settings until we find our setting
1824 // and then simulate a click on it to bring up the dialog
1825 final ListAdapter adapter = getPreferenceScreen().getRootAdapter();
1826 for (int idx = 0; idx < adapter.getCount(); idx++) {
1827 if (adapter.getItem(idx) == preference) {
1828 getPreferenceScreen().onItemClick(this.getListView(),
1829 null, idx, adapter.getItemId(idx));
1830 break;
1831 }
1832 }
1833 }
1834
1835 /**
1836 * Saves new VM provider settings associating them with the currently selected
1837 * provider if settings are different than the ones already stored for this
1838 * provider.
1839 * Later on these will be used when the user switches a provider.
1840 */
1841 private void maybeSaveSettingsForVoicemailProvider(String key,
Andrew Leeb490d732014-10-27 15:00:41 -07001842 VoicemailProviderSettings newSettings) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001843 if (mVoicemailProviders == null) {
1844 return;
1845 }
Andrew Leeb490d732014-10-27 15:00:41 -07001846 final VoicemailProviderSettings curSettings = loadSettingsForVoiceMailProvider(key);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001847 if (newSettings.equals(curSettings)) {
1848 if (DBG) {
1849 log("maybeSaveSettingsForVoicemailProvider:"
1850 + " Not saving setting for " + key + " since they have not changed");
1851 }
1852 return;
1853 }
1854 if (DBG) log("Saving settings for " + key + ": " + newSettings.toString());
1855 Editor editor = mPerProviderSavedVMNumbers.edit();
Andrew Leeb490d732014-10-27 15:00:41 -07001856 editor.putString(key + VM_NUMBER_TAG, newSettings.getVoicemailNumber());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001857 String fwdKey = key + FWD_SETTINGS_TAG;
Andrew Leeb490d732014-10-27 15:00:41 -07001858 CallForwardInfo[] s = newSettings.getForwardingSettings();
1859 if (s != VoicemailProviderSettings.NO_FORWARDING) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001860 editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, s.length);
1861 for (int i = 0; i < s.length; i++) {
1862 final String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i);
1863 final CallForwardInfo fi = s[i];
1864 editor.putInt(settingKey + FWD_SETTING_STATUS, fi.status);
1865 editor.putInt(settingKey + FWD_SETTING_REASON, fi.reason);
1866 editor.putString(settingKey + FWD_SETTING_NUMBER, fi.number);
1867 editor.putInt(settingKey + FWD_SETTING_TIME, fi.timeSeconds);
1868 }
1869 } else {
1870 editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0);
1871 }
1872 editor.apply();
1873 }
1874
1875 /**
1876 * Returns settings previously stored for the currently selected
1877 * voice mail provider. If none is stored returns null.
1878 * If the user switches to a voice mail provider and we have settings
1879 * stored for it we will automatically change the phone's voice mail number
1880 * and forwarding number to the stored one. Otherwise we will bring up provider's configuration
1881 * UI.
1882 */
Andrew Leeb490d732014-10-27 15:00:41 -07001883 private VoicemailProviderSettings loadSettingsForVoiceMailProvider(String key) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001884 final String vmNumberSetting = mPerProviderSavedVMNumbers.getString(key + VM_NUMBER_TAG,
1885 null);
1886 if (vmNumberSetting == null) {
1887 Log.w(LOG_TAG, "VoiceMailProvider settings for the key \"" + key + "\""
1888 + " was not found. Returning null.");
1889 return null;
1890 }
1891
Andrew Leeb490d732014-10-27 15:00:41 -07001892 CallForwardInfo[] cfi = VoicemailProviderSettings.NO_FORWARDING;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001893 String fwdKey = key + FWD_SETTINGS_TAG;
1894 final int fwdLen = mPerProviderSavedVMNumbers.getInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0);
1895 if (fwdLen > 0) {
1896 cfi = new CallForwardInfo[fwdLen];
1897 for (int i = 0; i < cfi.length; i++) {
1898 final String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i);
1899 cfi[i] = new CallForwardInfo();
1900 cfi[i].status = mPerProviderSavedVMNumbers.getInt(
1901 settingKey + FWD_SETTING_STATUS, 0);
1902 cfi[i].reason = mPerProviderSavedVMNumbers.getInt(
1903 settingKey + FWD_SETTING_REASON,
1904 CommandsInterface.CF_REASON_ALL_CONDITIONAL);
1905 cfi[i].serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
1906 cfi[i].toa = PhoneNumberUtils.TOA_International;
1907 cfi[i].number = mPerProviderSavedVMNumbers.getString(
1908 settingKey + FWD_SETTING_NUMBER, "");
1909 cfi[i].timeSeconds = mPerProviderSavedVMNumbers.getInt(
1910 settingKey + FWD_SETTING_TIME, 20);
1911 }
1912 }
1913
Andrew Leeb490d732014-10-27 15:00:41 -07001914 VoicemailProviderSettings settings = new VoicemailProviderSettings(vmNumberSetting, cfi);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001915 if (DBG) log("Loaded settings for " + key + ": " + settings.toString());
1916 return settings;
1917 }
1918
1919 /**
1920 * Deletes settings for the specified provider.
1921 */
1922 private void deleteSettingsForVoicemailProvider(String key) {
1923 if (DBG) log("Deleting settings for" + key);
1924 if (mVoicemailProviders == null) {
1925 return;
1926 }
1927 mPerProviderSavedVMNumbers.edit()
1928 .putString(key + VM_NUMBER_TAG, null)
1929 .putInt(key + FWD_SETTINGS_TAG + FWD_SETTINGS_LENGTH_TAG, 0)
1930 .commit();
1931 }
1932
1933 private String getCurrentVoicemailProviderKey() {
1934 final String key = mVoicemailProviders.getValue();
1935 return (key != null) ? key : DEFAULT_VM_PROVIDER_KEY;
1936 }
1937
1938 @Override
1939 public boolean onOptionsItemSelected(MenuItem item) {
1940 final int itemId = item.getItemId();
1941 if (itemId == android.R.id.home) { // See ActionBar#setDisplayHomeAsUpEnabled()
Yorke Leef2d0cac2013-09-09 19:42:56 -07001942 onBackPressed();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001943 return true;
1944 }
1945 return super.onOptionsItemSelected(item);
1946 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001947 /**
1948 * Finish current Activity and go up to the top level Settings ({@link CallFeaturesSetting}).
1949 * This is useful for implementing "HomeAsUp" capability for second-level Settings.
1950 */
1951 public static void goUpToTopLevelSetting(Activity activity) {
1952 Intent intent = new Intent(activity, CallFeaturesSetting.class);
1953 intent.setAction(Intent.ACTION_MAIN);
1954 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1955 activity.startActivity(intent);
1956 activity.finish();
1957 }
1958}