blob: 059a7f59951697b67aac8c2e43414d7f0b01122f [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 /** Event for Async voicemail change call */
195 private static final int EVENT_VOICEMAIL_CHANGED = 500;
196 private static final int EVENT_FORWARDING_CHANGED = 501;
197 private static final int EVENT_FORWARDING_GET_COMPLETED = 502;
198
Andrew Lee2170a972014-08-13 18:13:01 -0700199 private static final int MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY = 1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700200
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700201 public static final String HAC_KEY = "HACSetting";
202 public static final String HAC_VAL_ON = "ON";
203 public static final String HAC_VAL_OFF = "OFF";
204
205 /** Handle to voicemail pref */
206 private static final int VOICEMAIL_PREF_ID = 1;
207 private static final int VOICEMAIL_PROVIDER_CFG_ID = 2;
208
209 private Phone mPhone;
210
211 private AudioManager mAudioManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700212
213 private static final int VM_NOCHANGE_ERROR = 400;
214 private static final int VM_RESPONSE_ERROR = 500;
215 private static final int FW_SET_RESPONSE_ERROR = 501;
216 private static final int FW_GET_RESPONSE_ERROR = 502;
217
218
219 // dialog identifiers for voicemail
220 private static final int VOICEMAIL_DIALOG_CONFIRM = 600;
221 private static final int VOICEMAIL_FWD_SAVING_DIALOG = 601;
222 private static final int VOICEMAIL_FWD_READING_DIALOG = 602;
223 private static final int VOICEMAIL_REVERTING_DIALOG = 603;
224
225 // status message sent back from handlers
226 private static final int MSG_OK = 100;
227
228 // special statuses for voicemail controls.
229 private static final int MSG_VM_EXCEPTION = 400;
230 private static final int MSG_FW_SET_EXCEPTION = 401;
231 private static final int MSG_FW_GET_EXCEPTION = 402;
232 private static final int MSG_VM_OK = 600;
233 private static final int MSG_VM_NOCHANGE = 700;
234
235 // voicemail notification vibration string constants
236 private static final String VOICEMAIL_VIBRATION_ALWAYS = "always";
237 private static final String VOICEMAIL_VIBRATION_NEVER = "never";
238
239 private EditPhoneNumberPreference mSubMenuVoicemailSettings;
240
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700241 /** Whether dialpad plays DTMF tone or not. */
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700242 private CheckBoxPreference mButtonAutoRetry;
243 private CheckBoxPreference mButtonHAC;
244 private ListPreference mButtonDTMF;
245 private ListPreference mButtonTTY;
Andrew Leece8ae2a2014-09-10 10:41:48 -0700246 private Preference mPhoneAccountSettingsPreference;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700247 private ListPreference mVoicemailProviders;
Andrew Lee97708a42014-09-25 12:39:07 -0700248 private PreferenceScreen mVoicemailSettingsScreen;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700249 private PreferenceScreen mVoicemailSettings;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700250 private CheckBoxPreference mVoicemailNotificationVibrate;
Andrew Leedf14ead2014-10-17 14:22:52 -0700251 private CheckBoxPreference mEnableVideoCalling;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700252
253 private class VoiceMailProvider {
254 public VoiceMailProvider(String name, Intent intent) {
255 this.name = name;
256 this.intent = intent;
257 }
258 public String name;
259 public Intent intent;
260 }
261
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700262 private SharedPreferences mPerProviderSavedVMNumbers;
263
264 /**
265 * Results of reading forwarding settings
266 */
267 private CallForwardInfo[] mForwardingReadResults = null;
268
269 /**
270 * Result of forwarding number change.
271 * Keys are reasons (eg. unconditional forwarding).
272 */
273 private Map<Integer, AsyncResult> mForwardingChangeResults = null;
274
275 /**
276 * Expected CF read result types.
277 * This set keeps track of the CF types for which we've issued change
278 * commands so we can tell when we've received all of the responses.
279 */
280 private Collection<Integer> mExpectedChangeResultReasons = null;
281
282 /**
283 * Result of vm number change
284 */
285 private AsyncResult mVoicemailChangeResult = null;
286
287 /**
288 * Previous VM provider setting so we can return to it in case of failure.
289 */
290 private String mPreviousVMProviderKey = null;
291
292 /**
293 * Id of the dialog being currently shown.
294 */
295 private int mCurrentDialogId = 0;
296
297 /**
298 * Flag indicating that we are invoking settings for the voicemail provider programmatically
299 * due to vm provider change.
300 */
301 private boolean mVMProviderSettingsForced = false;
302
303 /**
304 * Flag indicating that we are making changes to vm or fwd numbers
305 * due to vm provider change.
306 */
307 private boolean mChangingVMorFwdDueToProviderChange = false;
308
309 /**
310 * True if we are in the process of vm & fwd number change and vm has already been changed.
311 * This is used to decide what to do in case of rollback.
312 */
313 private boolean mVMChangeCompletedSuccessfully = false;
314
315 /**
316 * True if we had full or partial failure setting forwarding numbers and so need to roll them
317 * back.
318 */
319 private boolean mFwdChangesRequireRollback = false;
320
321 /**
322 * Id of error msg to display to user once we are done reverting the VM provider to the previous
323 * one.
324 */
325 private int mVMOrFwdSetError = 0;
326
327 /**
328 * Data about discovered voice mail settings providers.
329 * Is populated by querying which activities can handle ACTION_CONFIGURE_VOICEMAIL.
330 * They key in this map is package name + activity name.
331 * We always add an entry for the default provider with a key of empty
332 * string and intent value of null.
333 * @see #initVoiceMailProviders()
334 */
335 private final Map<String, VoiceMailProvider> mVMProvidersData =
336 new HashMap<String, VoiceMailProvider>();
337
338 /** string to hold old voicemail number as it is being updated. */
339 private String mOldVmNumber;
340
341 // New call forwarding settings and vm number we will be setting
342 // Need to save these since before we get to saving we need to asynchronously
343 // query the existing forwarding settings.
344 private CallForwardInfo[] mNewFwdSettings;
345 private String mNewVMNumber;
346
347 private boolean mForeground;
348
349 @Override
350 public void onPause() {
351 super.onPause();
352 mForeground = false;
353 }
354
355 /**
356 * We have to pull current settings from the network for all kinds of
357 * voicemail providers so we can tell whether we have to update them,
358 * so use this bit to keep track of whether we're reading settings for the
359 * default provider and should therefore save them out when done.
360 */
361 private boolean mReadingSettingsForDefaultProvider = false;
362
Tyler Gunnbaee2952014-09-10 16:01:02 -0700363 /**
364 * Used to indicate that the voicemail preference should be shown.
365 */
366 private boolean mShowVoicemailPreference = false;
367
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700368 /*
369 * Click Listeners, handle click based on objects attached to UI.
370 */
371
372 // Click listener for all toggle events
373 @Override
374 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
375 if (preference == mSubMenuVoicemailSettings) {
376 return true;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700377 } else if (preference == mButtonDTMF) {
378 return true;
379 } else if (preference == mButtonTTY) {
380 return true;
381 } else if (preference == mButtonAutoRetry) {
382 android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
383 android.provider.Settings.Global.CALL_AUTO_RETRY,
384 mButtonAutoRetry.isChecked() ? 1 : 0);
385 return true;
386 } else if (preference == mButtonHAC) {
387 int hac = mButtonHAC.isChecked() ? 1 : 0;
388 // Update HAC value in Settings database
389 Settings.System.putInt(mPhone.getContext().getContentResolver(),
390 Settings.System.HEARING_AID, hac);
391
392 // Update HAC Value in AudioManager
393 mAudioManager.setParameter(HAC_KEY, hac != 0 ? HAC_VAL_ON : HAC_VAL_OFF);
394 return true;
395 } else if (preference == mVoicemailSettings) {
Yorke Leea0f63bf2014-10-09 18:27:20 -0700396 final Dialog dialog = mVoicemailSettings.getDialog();
397 if (dialog != null) {
398 dialog.getActionBar().setDisplayHomeAsUpEnabled(false);
399 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700400 if (DBG) log("onPreferenceTreeClick: Voicemail Settings Preference is clicked.");
401 if (preference.getIntent() != null) {
402 if (DBG) {
403 log("onPreferenceTreeClick: Invoking cfg intent "
404 + preference.getIntent().getPackage());
405 }
406
407 // onActivityResult() will be responsible for resetting some of variables.
408 this.startActivityForResult(preference.getIntent(), VOICEMAIL_PROVIDER_CFG_ID);
409 return true;
410 } else {
411 if (DBG) {
412 log("onPreferenceTreeClick:"
413 + " No Intent is available. Use default behavior defined in xml.");
414 }
415
416 // There's no onActivityResult(), so we need to take care of some of variables
417 // which should be reset here.
418 mPreviousVMProviderKey = DEFAULT_VM_PROVIDER_KEY;
419 mVMProviderSettingsForced = false;
420
421 // This should let the preference use default behavior in the xml.
422 return false;
423 }
Andrew Lee97708a42014-09-25 12:39:07 -0700424 } else if (preference == mVoicemailSettingsScreen) {
Yorke Leea0f63bf2014-10-09 18:27:20 -0700425 final Dialog dialog = mVoicemailSettingsScreen.getDialog();
426 if (dialog != null) {
427 dialog.getActionBar().setDisplayHomeAsUpEnabled(false);
428 }
Andrew Lee97708a42014-09-25 12:39:07 -0700429 return false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700430 }
431 return false;
432 }
433
434 /**
435 * Implemented to support onPreferenceChangeListener to look for preference
436 * changes.
437 *
438 * @param preference is the preference to be changed
439 * @param objValue should be the value of the selection, NOT its localized
440 * display value.
441 */
442 @Override
443 public boolean onPreferenceChange(Preference preference, Object objValue) {
444 if (DBG) {
Andrew Leedf14ead2014-10-17 14:22:52 -0700445 log("onPreferenceChange(). preference: \"" + preference + "\""
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700446 + ", value: \"" + objValue + "\"");
447 }
Andrew Lee2170a972014-08-13 18:13:01 -0700448
449 if (preference == mButtonDTMF) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700450 int index = mButtonDTMF.findIndexOfValue((String) objValue);
451 Settings.System.putInt(mPhone.getContext().getContentResolver(),
452 Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, index);
453 } else if (preference == mButtonTTY) {
454 handleTTYChange(preference, objValue);
455 } else if (preference == mVoicemailProviders) {
456 final String newProviderKey = (String) objValue;
457 if (DBG) {
458 log("Voicemail Provider changes from \"" + mPreviousVMProviderKey
459 + "\" to \"" + newProviderKey + "\".");
460 }
461 // If previous provider key and the new one is same, we don't need to handle it.
462 if (mPreviousVMProviderKey.equals(newProviderKey)) {
463 if (DBG) log("No change is made toward VM provider setting.");
464 return true;
465 }
466 updateVMPreferenceWidgets(newProviderKey);
467
Andrew Leeb490d732014-10-27 15:00:41 -0700468 final VoicemailProviderSettings newProviderSettings =
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700469 loadSettingsForVoiceMailProvider(newProviderKey);
470
471 // If the user switches to a voice mail provider and we have a
472 // numbers stored for it we will automatically change the
473 // phone's
474 // voice mail and forwarding number to the stored ones.
475 // Otherwise we will bring up provider's configuration UI.
476
477 if (newProviderSettings == null) {
478 // Force the user into a configuration of the chosen provider
479 Log.w(LOG_TAG, "Saved preferences not found - invoking config");
480 mVMProviderSettingsForced = true;
481 simulatePreferenceClick(mVoicemailSettings);
482 } else {
483 if (DBG) log("Saved preferences found - switching to them");
484 // Set this flag so if we get a failure we revert to previous provider
485 mChangingVMorFwdDueToProviderChange = true;
486 saveVoiceMailAndForwardingNumber(newProviderKey, newProviderSettings);
487 }
Andrew Leedf14ead2014-10-17 14:22:52 -0700488 } else if (preference == mEnableVideoCalling) {
Andrew Lee312e8172014-10-23 17:01:36 -0700489 if (ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())) {
490 PhoneGlobals.getInstance().phoneMgr.enableVideoCalling((boolean) objValue);
491 } else {
492 AlertDialog.Builder builder = new AlertDialog.Builder(this);
493 DialogInterface.OnClickListener networkSettingsClickListener =
494 new Dialog.OnClickListener() {
495 @Override
496 public void onClick(DialogInterface dialog, int which) {
497 startActivity(new Intent(mPhone.getContext(),
498 com.android.phone.MobileNetworkSettings.class));
499 }
500 };
501 builder.setMessage(getResources().getString(
502 R.string.enable_video_calling_dialog_msg))
503 .setNeutralButton(getResources().getString(
504 R.string.enable_video_calling_dialog_settings),
505 networkSettingsClickListener)
506 .setPositiveButton(android.R.string.ok, null)
507 .show();
508 return false;
509 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700510 }
511 // always let the preference setting proceed.
512 return true;
513 }
514
515 @Override
516 public void onDialogClosed(EditPhoneNumberPreference preference, int buttonClicked) {
517 if (DBG) log("onPreferenceClick: request preference click on dialog close: " +
518 buttonClicked);
519 if (buttonClicked == DialogInterface.BUTTON_NEGATIVE) {
520 return;
521 }
522
523 if (preference == mSubMenuVoicemailSettings) {
524 handleVMBtnClickRequest();
525 }
526 }
527
528 /**
529 * Implemented for EditPhoneNumberPreference.GetDefaultNumberListener.
530 * This method set the default values for the various
531 * EditPhoneNumberPreference dialogs.
532 */
533 @Override
534 public String onGetDefaultNumber(EditPhoneNumberPreference preference) {
535 if (preference == mSubMenuVoicemailSettings) {
536 // update the voicemail number field, which takes care of the
537 // mSubMenuVoicemailSettings itself, so we should return null.
538 if (DBG) log("updating default for voicemail dialog");
539 updateVoiceNumberField();
540 return null;
541 }
542
543 String vmDisplay = mPhone.getVoiceMailNumber();
544 if (TextUtils.isEmpty(vmDisplay)) {
545 // if there is no voicemail number, we just return null to
546 // indicate no contribution.
547 return null;
548 }
549
550 // Return the voicemail number prepended with "VM: "
551 if (DBG) log("updating default for call forwarding dialogs");
552 return getString(R.string.voicemail_abbreviated) + " " + vmDisplay;
553 }
554
555
556 // override the startsubactivity call to make changes in state consistent.
557 @Override
558 public void startActivityForResult(Intent intent, int requestCode) {
559 if (requestCode == -1) {
560 // this is an intent requested from the preference framework.
561 super.startActivityForResult(intent, requestCode);
562 return;
563 }
564
565 if (DBG) log("startSubActivity: starting requested subactivity");
566 super.startActivityForResult(intent, requestCode);
567 }
568
569 private void switchToPreviousVoicemailProvider() {
570 if (DBG) log("switchToPreviousVoicemailProvider " + mPreviousVMProviderKey);
571 if (mPreviousVMProviderKey != null) {
572 if (mVMChangeCompletedSuccessfully || mFwdChangesRequireRollback) {
573 // we have to revert with carrier
574 if (DBG) {
575 log("Needs to rollback."
576 + " mVMChangeCompletedSuccessfully=" + mVMChangeCompletedSuccessfully
577 + ", mFwdChangesRequireRollback=" + mFwdChangesRequireRollback);
578 }
579
580 showDialogIfForeground(VOICEMAIL_REVERTING_DIALOG);
Andrew Leeb490d732014-10-27 15:00:41 -0700581 final VoicemailProviderSettings prevSettings =
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700582 loadSettingsForVoiceMailProvider(mPreviousVMProviderKey);
583 if (prevSettings == null) {
584 // prevSettings never becomes null since it should be already loaded!
Andrew Leeb490d732014-10-27 15:00:41 -0700585 Log.e(LOG_TAG, "VoicemailProviderSettings for the key \""
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700586 + mPreviousVMProviderKey + "\" becomes null, which is unexpected.");
587 if (DBG) {
588 Log.e(LOG_TAG,
589 "mVMChangeCompletedSuccessfully: " + mVMChangeCompletedSuccessfully
590 + ", mFwdChangesRequireRollback: " + mFwdChangesRequireRollback);
591 }
592 }
593 if (mVMChangeCompletedSuccessfully) {
Andrew Leeb490d732014-10-27 15:00:41 -0700594 mNewVMNumber = prevSettings.getVoicemailNumber();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700595 Log.i(LOG_TAG, "VM change is already completed successfully."
596 + "Have to revert VM back to " + mNewVMNumber + " again.");
597 mPhone.setVoiceMailNumber(
598 mPhone.getVoiceMailAlphaTag().toString(),
599 mNewVMNumber,
600 Message.obtain(mRevertOptionComplete, EVENT_VOICEMAIL_CHANGED));
601 }
602 if (mFwdChangesRequireRollback) {
603 Log.i(LOG_TAG, "Requested to rollback Fwd changes.");
Andrew Leeb490d732014-10-27 15:00:41 -0700604 final CallForwardInfo[] prevFwdSettings = prevSettings.getForwardingSettings();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700605 if (prevFwdSettings != null) {
606 Map<Integer, AsyncResult> results =
607 mForwardingChangeResults;
608 resetForwardingChangeState();
609 for (int i = 0; i < prevFwdSettings.length; i++) {
610 CallForwardInfo fi = prevFwdSettings[i];
611 if (DBG) log("Reverting fwd #: " + i + ": " + fi.toString());
612 // Only revert the settings for which the update
613 // succeeded
614 AsyncResult result = results.get(fi.reason);
615 if (result != null && result.exception == null) {
616 mExpectedChangeResultReasons.add(fi.reason);
617 mPhone.setCallForwardingOption(
618 (fi.status == 1 ?
619 CommandsInterface.CF_ACTION_REGISTRATION :
620 CommandsInterface.CF_ACTION_DISABLE),
621 fi.reason,
622 fi.number,
623 fi.timeSeconds,
624 mRevertOptionComplete.obtainMessage(
625 EVENT_FORWARDING_CHANGED, i, 0));
626 }
627 }
628 }
629 }
630 } else {
631 if (DBG) log("No need to revert");
632 onRevertDone();
633 }
634 }
635 }
636
637 private void onRevertDone() {
638 if (DBG) log("Flipping provider key back to " + mPreviousVMProviderKey);
639 mVoicemailProviders.setValue(mPreviousVMProviderKey);
640 updateVMPreferenceWidgets(mPreviousVMProviderKey);
641 updateVoiceNumberField();
642 if (mVMOrFwdSetError != 0) {
643 showVMDialog(mVMOrFwdSetError);
644 mVMOrFwdSetError = 0;
645 }
646 }
647
648 @Override
649 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
650 if (DBG) {
651 log("onActivityResult: requestCode: " + requestCode
652 + ", resultCode: " + resultCode
653 + ", data: " + data);
654 }
655 // there are cases where the contact picker may end up sending us more than one
656 // request. We want to ignore the request if we're not in the correct state.
657 if (requestCode == VOICEMAIL_PROVIDER_CFG_ID) {
658 boolean failure = false;
659
660 // No matter how the processing of result goes lets clear the flag
661 if (DBG) log("mVMProviderSettingsForced: " + mVMProviderSettingsForced);
662 final boolean isVMProviderSettingsForced = mVMProviderSettingsForced;
663 mVMProviderSettingsForced = false;
664
665 String vmNum = null;
666 if (resultCode != RESULT_OK) {
667 if (DBG) log("onActivityResult: vm provider cfg result not OK.");
668 failure = true;
669 } else {
670 if (data == null) {
671 if (DBG) log("onActivityResult: vm provider cfg result has no data");
672 failure = true;
673 } else {
674 if (data.getBooleanExtra(SIGNOUT_EXTRA, false)) {
675 if (DBG) log("Provider requested signout");
676 if (isVMProviderSettingsForced) {
677 if (DBG) log("Going back to previous provider on signout");
678 switchToPreviousVoicemailProvider();
679 } else {
680 final String victim = getCurrentVoicemailProviderKey();
681 if (DBG) log("Relaunching activity and ignoring " + victim);
682 Intent i = new Intent(ACTION_ADD_VOICEMAIL);
683 i.putExtra(IGNORE_PROVIDER_EXTRA, victim);
684 i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
685 this.startActivity(i);
686 }
687 return;
688 }
689 vmNum = data.getStringExtra(VM_NUMBER_EXTRA);
690 if (vmNum == null || vmNum.length() == 0) {
691 if (DBG) log("onActivityResult: vm provider cfg result has no vmnum");
692 failure = true;
693 }
694 }
695 }
696 if (failure) {
697 if (DBG) log("Failure in return from voicemail provider");
698 if (isVMProviderSettingsForced) {
699 switchToPreviousVoicemailProvider();
700 } else {
701 if (DBG) log("Not switching back the provider since this is not forced config");
702 }
703 return;
704 }
705 mChangingVMorFwdDueToProviderChange = isVMProviderSettingsForced;
706 final String fwdNum = data.getStringExtra(FWD_NUMBER_EXTRA);
707
Santos Cordonda120f42014-08-06 04:44:34 -0700708 // TODO: It would be nice to load the current network setting for this and
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700709 // send it to the provider when it's config is invoked so it can use this as default
710 final int fwdNumTime = data.getIntExtra(FWD_NUMBER_TIME_EXTRA, 20);
711
712 if (DBG) log("onActivityResult: vm provider cfg result " +
713 (fwdNum != null ? "has" : " does not have") + " forwarding number");
714 saveVoiceMailAndForwardingNumber(getCurrentVoicemailProviderKey(),
Andrew Leeb490d732014-10-27 15:00:41 -0700715 new VoicemailProviderSettings(vmNum, fwdNum, fwdNumTime));
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700716 return;
717 }
718
719 if (requestCode == VOICEMAIL_PREF_ID) {
720 if (resultCode != RESULT_OK) {
721 if (DBG) log("onActivityResult: contact picker result not OK.");
722 return;
723 }
724
725 Cursor cursor = null;
726 try {
727 cursor = getContentResolver().query(data.getData(),
728 NUM_PROJECTION, null, null, null);
729 if ((cursor == null) || (!cursor.moveToFirst())) {
730 if (DBG) log("onActivityResult: bad contact data, no results found.");
731 return;
732 }
733 mSubMenuVoicemailSettings.onPickActivityResult(cursor.getString(0));
734 return;
735 } finally {
736 if (cursor != null) {
737 cursor.close();
738 }
739 }
740 }
741
742 super.onActivityResult(requestCode, resultCode, data);
743 }
744
745 // Voicemail button logic
746 private void handleVMBtnClickRequest() {
747 // normally called on the dialog close.
748
749 // Since we're stripping the formatting out on the getPhoneNumber()
750 // call now, we won't need to do so here anymore.
751
752 saveVoiceMailAndForwardingNumber(
753 getCurrentVoicemailProviderKey(),
Andrew Leeb490d732014-10-27 15:00:41 -0700754 new VoicemailProviderSettings(mSubMenuVoicemailSettings.getPhoneNumber(),
755 VoicemailProviderSettings.NO_FORWARDING)
Tyler Gunn4d45d1c2014-09-12 22:17:53 -0700756 );
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700757 }
758
759
760 /**
761 * Wrapper around showDialog() that will silently do nothing if we're
762 * not in the foreground.
763 *
764 * This is useful here because most of the dialogs we display from
765 * this class are triggered by asynchronous events (like
766 * success/failure messages from the telephony layer) and it's
767 * possible for those events to come in even after the user has gone
768 * to a different screen.
769 */
770 // TODO: this is too brittle: it's still easy to accidentally add new
771 // code here that calls showDialog() directly (which will result in a
772 // WindowManager$BadTokenException if called after the activity has
773 // been stopped.)
774 //
775 // It would be cleaner to do the "if (mForeground)" check in one
776 // central place, maybe by using a single Handler for all asynchronous
777 // events (and have *that* discard events if we're not in the
778 // foreground.)
779 //
780 // Unfortunately it's not that simple, since we sometimes need to do
781 // actual work to handle these events whether or not we're in the
782 // foreground (see the Handler code in mSetOptionComplete for
783 // example.)
784 private void showDialogIfForeground(int id) {
785 if (mForeground) {
786 showDialog(id);
787 }
788 }
789
790 private void dismissDialogSafely(int id) {
791 try {
792 dismissDialog(id);
793 } catch (IllegalArgumentException e) {
794 // This is expected in the case where we were in the background
795 // at the time we would normally have shown the dialog, so we didn't
796 // show it.
797 }
798 }
799
Andrew Leeb490d732014-10-27 15:00:41 -0700800 private void saveVoiceMailAndForwardingNumber(
801 String key, VoicemailProviderSettings newSettings) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700802 if (DBG) log("saveVoiceMailAndForwardingNumber: " + newSettings.toString());
Andrew Leeb490d732014-10-27 15:00:41 -0700803 mNewVMNumber = newSettings.getVoicemailNumber();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700804 // empty vm number == clearing the vm number ?
805 if (mNewVMNumber == null) {
806 mNewVMNumber = "";
807 }
808
Andrew Leeb490d732014-10-27 15:00:41 -0700809 mNewFwdSettings = newSettings.getForwardingSettings();
810 if (DBG) log("newFwdNumber "
811 + String.valueOf((mNewFwdSettings != null ? mNewFwdSettings.length : 0))
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700812 + " settings");
813
814 // No fwd settings on CDMA
815 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
816 if (DBG) log("ignoring forwarding setting since this is CDMA phone");
Andrew Leeb490d732014-10-27 15:00:41 -0700817 mNewFwdSettings = VoicemailProviderSettings.NO_FORWARDING;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700818 }
819
Andrew Leee3c15212014-10-28 13:12:55 -0700820 // Throw a warning if the voicemail is the same and we did not change forwarding.
Andrew Leeb490d732014-10-27 15:00:41 -0700821 if (mNewVMNumber.equals(mOldVmNumber)
822 && mNewFwdSettings == VoicemailProviderSettings.NO_FORWARDING) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700823 showVMDialog(MSG_VM_NOCHANGE);
824 return;
825 }
826
827 maybeSaveSettingsForVoicemailProvider(key, newSettings);
828 mVMChangeCompletedSuccessfully = false;
829 mFwdChangesRequireRollback = false;
830 mVMOrFwdSetError = 0;
831 if (!key.equals(mPreviousVMProviderKey)) {
832 mReadingSettingsForDefaultProvider =
833 mPreviousVMProviderKey.equals(DEFAULT_VM_PROVIDER_KEY);
834 if (DBG) log("Reading current forwarding settings");
Andrew Leeb490d732014-10-27 15:00:41 -0700835 int numSettingsReasons = VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS.length;
836 mForwardingReadResults = new CallForwardInfo[numSettingsReasons];
837 for (int i = 0; i < mForwardingReadResults.length; i++) {
838 mPhone.getCallForwardingOption(
839 VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS[i],
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700840 mGetOptionComplete.obtainMessage(EVENT_FORWARDING_GET_COMPLETED, i, 0));
841 }
842 showDialogIfForeground(VOICEMAIL_FWD_READING_DIALOG);
843 } else {
844 saveVoiceMailAndForwardingNumberStage2();
845 }
846 }
847
848 private final Handler mGetOptionComplete = new Handler() {
849 @Override
850 public void handleMessage(Message msg) {
851 AsyncResult result = (AsyncResult) msg.obj;
852 switch (msg.what) {
853 case EVENT_FORWARDING_GET_COMPLETED:
854 handleForwardingSettingsReadResult(result, msg.arg1);
855 break;
856 }
857 }
858 };
859
860 private void handleForwardingSettingsReadResult(AsyncResult ar, int idx) {
861 if (DBG) Log.d(LOG_TAG, "handleForwardingSettingsReadResult: " + idx);
862 Throwable error = null;
863 if (ar.exception != null) {
864 if (DBG) Log.d(LOG_TAG, "FwdRead: ar.exception=" +
865 ar.exception.getMessage());
866 error = ar.exception;
867 }
868 if (ar.userObj instanceof Throwable) {
869 if (DBG) Log.d(LOG_TAG, "FwdRead: userObj=" +
870 ((Throwable)ar.userObj).getMessage());
871 error = (Throwable)ar.userObj;
872 }
873
874 // We may have already gotten an error and decided to ignore the other results.
875 if (mForwardingReadResults == null) {
876 if (DBG) Log.d(LOG_TAG, "ignoring fwd reading result: " + idx);
877 return;
878 }
879
880 // In case of error ignore other results, show an error dialog
881 if (error != null) {
882 if (DBG) Log.d(LOG_TAG, "Error discovered for fwd read : " + idx);
883 mForwardingReadResults = null;
884 dismissDialogSafely(VOICEMAIL_FWD_READING_DIALOG);
885 showVMDialog(MSG_FW_GET_EXCEPTION);
886 return;
887 }
888
889 // Get the forwarding info
890 final CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result;
891 CallForwardInfo fi = null;
892 for (int i = 0 ; i < cfInfoArray.length; i++) {
893 if ((cfInfoArray[i].serviceClass & CommandsInterface.SERVICE_CLASS_VOICE) != 0) {
894 fi = cfInfoArray[i];
895 break;
896 }
897 }
898 if (fi == null) {
899
900 // In case we go nothing it means we need this reason disabled
901 // so create a CallForwardInfo for capturing this
902 if (DBG) Log.d(LOG_TAG, "Creating default info for " + idx);
903 fi = new CallForwardInfo();
904 fi.status = 0;
Andrew Leeb490d732014-10-27 15:00:41 -0700905 fi.reason = VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS[idx];
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700906 fi.serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
907 } else {
908 // if there is not a forwarding number, ensure the entry is set to "not active."
909 if (fi.number == null || fi.number.length() == 0) {
910 fi.status = 0;
911 }
912
913 if (DBG) Log.d(LOG_TAG, "Got " + fi.toString() + " for " + idx);
914 }
915 mForwardingReadResults[idx] = fi;
916
917 // Check if we got all the results already
918 boolean done = true;
919 for (int i = 0; i < mForwardingReadResults.length; i++) {
920 if (mForwardingReadResults[i] == null) {
921 done = false;
922 break;
923 }
924 }
925 if (done) {
926 if (DBG) Log.d(LOG_TAG, "Done receiving fwd info");
927 dismissDialogSafely(VOICEMAIL_FWD_READING_DIALOG);
928 if (mReadingSettingsForDefaultProvider) {
929 maybeSaveSettingsForVoicemailProvider(DEFAULT_VM_PROVIDER_KEY,
Andrew Leeb490d732014-10-27 15:00:41 -0700930 new VoicemailProviderSettings(this.mOldVmNumber,
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700931 mForwardingReadResults));
932 mReadingSettingsForDefaultProvider = false;
933 }
934 saveVoiceMailAndForwardingNumberStage2();
935 } else {
936 if (DBG) Log.d(LOG_TAG, "Not done receiving fwd info");
937 }
938 }
939
940 private CallForwardInfo infoForReason(CallForwardInfo[] infos, int reason) {
941 CallForwardInfo result = null;
942 if (null != infos) {
943 for (CallForwardInfo info : infos) {
944 if (info.reason == reason) {
945 result = info;
946 break;
947 }
948 }
949 }
950 return result;
951 }
952
953 private boolean isUpdateRequired(CallForwardInfo oldInfo,
954 CallForwardInfo newInfo) {
955 boolean result = true;
956 if (0 == newInfo.status) {
957 // If we're disabling a type of forwarding, and it's already
958 // disabled for the account, don't make any change
959 if (oldInfo != null && oldInfo.status == 0) {
960 result = false;
961 }
962 }
963 return result;
964 }
965
966 private void resetForwardingChangeState() {
967 mForwardingChangeResults = new HashMap<Integer, AsyncResult>();
968 mExpectedChangeResultReasons = new HashSet<Integer>();
969 }
970
971 // Called after we are done saving the previous forwarding settings if
972 // we needed.
973 private void saveVoiceMailAndForwardingNumberStage2() {
974 mForwardingChangeResults = null;
975 mVoicemailChangeResult = null;
Andrew Leeb490d732014-10-27 15:00:41 -0700976 if (mNewFwdSettings != VoicemailProviderSettings.NO_FORWARDING) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700977 resetForwardingChangeState();
978 for (int i = 0; i < mNewFwdSettings.length; i++) {
979 CallForwardInfo fi = mNewFwdSettings[i];
980
981 final boolean doUpdate = isUpdateRequired(infoForReason(
982 mForwardingReadResults, fi.reason), fi);
983
984 if (doUpdate) {
985 if (DBG) log("Setting fwd #: " + i + ": " + fi.toString());
986 mExpectedChangeResultReasons.add(i);
987
988 mPhone.setCallForwardingOption(
989 fi.status == 1 ?
990 CommandsInterface.CF_ACTION_REGISTRATION :
991 CommandsInterface.CF_ACTION_DISABLE,
992 fi.reason,
993 fi.number,
994 fi.timeSeconds,
995 mSetOptionComplete.obtainMessage(
996 EVENT_FORWARDING_CHANGED, fi.reason, 0));
997 }
998 }
999 showDialogIfForeground(VOICEMAIL_FWD_SAVING_DIALOG);
1000 } else {
1001 if (DBG) log("Not touching fwd #");
1002 setVMNumberWithCarrier();
1003 }
1004 }
1005
1006 private void setVMNumberWithCarrier() {
1007 if (DBG) log("save voicemail #: " + mNewVMNumber);
1008 mPhone.setVoiceMailNumber(
1009 mPhone.getVoiceMailAlphaTag().toString(),
1010 mNewVMNumber,
1011 Message.obtain(mSetOptionComplete, EVENT_VOICEMAIL_CHANGED));
1012 }
1013
1014 /**
1015 * Callback to handle option update completions
1016 */
1017 private final Handler mSetOptionComplete = new Handler() {
1018 @Override
1019 public void handleMessage(Message msg) {
1020 AsyncResult result = (AsyncResult) msg.obj;
1021 boolean done = false;
1022 switch (msg.what) {
1023 case EVENT_VOICEMAIL_CHANGED:
1024 mVoicemailChangeResult = result;
1025 mVMChangeCompletedSuccessfully = checkVMChangeSuccess() == null;
1026 if (DBG) log("VM change complete msg, VM change done = " +
1027 String.valueOf(mVMChangeCompletedSuccessfully));
1028 done = true;
1029 break;
1030 case EVENT_FORWARDING_CHANGED:
1031 mForwardingChangeResults.put(msg.arg1, result);
1032 if (result.exception != null) {
1033 Log.w(LOG_TAG, "Error in setting fwd# " + msg.arg1 + ": " +
1034 result.exception.getMessage());
1035 } else {
1036 if (DBG) log("Success in setting fwd# " + msg.arg1);
1037 }
1038 final boolean completed = checkForwardingCompleted();
1039 if (completed) {
1040 if (checkFwdChangeSuccess() == null) {
1041 if (DBG) log("Overall fwd changes completed ok, starting vm change");
1042 setVMNumberWithCarrier();
1043 } else {
1044 Log.w(LOG_TAG, "Overall fwd changes completed in failure. " +
1045 "Check if we need to try rollback for some settings.");
1046 mFwdChangesRequireRollback = false;
1047 Iterator<Map.Entry<Integer,AsyncResult>> it =
1048 mForwardingChangeResults.entrySet().iterator();
1049 while (it.hasNext()) {
1050 Map.Entry<Integer,AsyncResult> entry = it.next();
1051 if (entry.getValue().exception == null) {
1052 // If at least one succeeded we have to revert
1053 Log.i(LOG_TAG, "Rollback will be required");
1054 mFwdChangesRequireRollback = true;
1055 break;
1056 }
1057 }
1058 if (!mFwdChangesRequireRollback) {
1059 Log.i(LOG_TAG, "No rollback needed.");
1060 }
1061 done = true;
1062 }
1063 }
1064 break;
1065 default:
1066 // TODO: should never reach this, may want to throw exception
1067 }
1068 if (done) {
1069 if (DBG) log("All VM provider related changes done");
1070 if (mForwardingChangeResults != null) {
1071 dismissDialogSafely(VOICEMAIL_FWD_SAVING_DIALOG);
1072 }
1073 handleSetVMOrFwdMessage();
1074 }
1075 }
1076 };
1077
1078 /**
1079 * Callback to handle option revert completions
1080 */
1081 private final Handler mRevertOptionComplete = new Handler() {
1082 @Override
1083 public void handleMessage(Message msg) {
1084 AsyncResult result = (AsyncResult) msg.obj;
1085 switch (msg.what) {
1086 case EVENT_VOICEMAIL_CHANGED:
1087 mVoicemailChangeResult = result;
1088 if (DBG) log("VM revert complete msg");
1089 break;
1090 case EVENT_FORWARDING_CHANGED:
1091 mForwardingChangeResults.put(msg.arg1, result);
1092 if (result.exception != null) {
1093 if (DBG) log("Error in reverting fwd# " + msg.arg1 + ": " +
1094 result.exception.getMessage());
1095 } else {
1096 if (DBG) log("Success in reverting fwd# " + msg.arg1);
1097 }
1098 if (DBG) log("FWD revert complete msg ");
1099 break;
1100 default:
1101 // TODO: should never reach this, may want to throw exception
1102 }
1103 final boolean done =
1104 (!mVMChangeCompletedSuccessfully || mVoicemailChangeResult != null) &&
1105 (!mFwdChangesRequireRollback || checkForwardingCompleted());
1106 if (done) {
1107 if (DBG) log("All VM reverts done");
1108 dismissDialogSafely(VOICEMAIL_REVERTING_DIALOG);
1109 onRevertDone();
1110 }
1111 }
1112 };
1113
1114 /**
1115 * @return true if forwarding change has completed
1116 */
1117 private boolean checkForwardingCompleted() {
1118 boolean result;
1119 if (mForwardingChangeResults == null) {
1120 result = true;
1121 } else {
1122 // return true iff there is a change result for every reason for
1123 // which we expected a result
1124 result = true;
1125 for (Integer reason : mExpectedChangeResultReasons) {
1126 if (mForwardingChangeResults.get(reason) == null) {
1127 result = false;
1128 break;
1129 }
1130 }
1131 }
1132 return result;
1133 }
1134 /**
1135 * @return error string or null if successful
1136 */
1137 private String checkFwdChangeSuccess() {
1138 String result = null;
1139 Iterator<Map.Entry<Integer,AsyncResult>> it =
1140 mForwardingChangeResults.entrySet().iterator();
1141 while (it.hasNext()) {
1142 Map.Entry<Integer,AsyncResult> entry = it.next();
1143 Throwable exception = entry.getValue().exception;
1144 if (exception != null) {
1145 result = exception.getMessage();
1146 if (result == null) {
1147 result = "";
1148 }
1149 break;
1150 }
1151 }
1152 return result;
1153 }
1154
1155 /**
1156 * @return error string or null if successful
1157 */
1158 private String checkVMChangeSuccess() {
1159 if (mVoicemailChangeResult.exception != null) {
1160 final String msg = mVoicemailChangeResult.exception.getMessage();
1161 if (msg == null) {
1162 return "";
1163 }
1164 return msg;
1165 }
1166 return null;
1167 }
1168
1169 private void handleSetVMOrFwdMessage() {
1170 if (DBG) {
1171 log("handleSetVMMessage: set VM request complete");
1172 }
1173 boolean success = true;
1174 boolean fwdFailure = false;
1175 String exceptionMessage = "";
1176 if (mForwardingChangeResults != null) {
1177 exceptionMessage = checkFwdChangeSuccess();
1178 if (exceptionMessage != null) {
1179 success = false;
1180 fwdFailure = true;
1181 }
1182 }
1183 if (success) {
1184 exceptionMessage = checkVMChangeSuccess();
1185 if (exceptionMessage != null) {
1186 success = false;
1187 }
1188 }
1189 if (success) {
1190 if (DBG) log("change VM success!");
1191 handleVMAndFwdSetSuccess(MSG_VM_OK);
1192 } else {
1193 if (fwdFailure) {
1194 Log.w(LOG_TAG, "Failed to change fowarding setting. Reason: " + exceptionMessage);
1195 handleVMOrFwdSetError(MSG_FW_SET_EXCEPTION);
1196 } else {
1197 Log.w(LOG_TAG, "Failed to change voicemail. Reason: " + exceptionMessage);
1198 handleVMOrFwdSetError(MSG_VM_EXCEPTION);
1199 }
1200 }
1201 }
1202
1203 /**
1204 * Called when Voicemail Provider or its forwarding settings failed. Rolls back partly made
1205 * changes to those settings and show "failure" dialog.
1206 *
1207 * @param msgId Message ID used for the specific error case. {@link #MSG_FW_SET_EXCEPTION} or
1208 * {@link #MSG_VM_EXCEPTION}
1209 */
1210 private void handleVMOrFwdSetError(int msgId) {
1211 if (mChangingVMorFwdDueToProviderChange) {
1212 mVMOrFwdSetError = msgId;
1213 mChangingVMorFwdDueToProviderChange = false;
1214 switchToPreviousVoicemailProvider();
1215 return;
1216 }
1217 mChangingVMorFwdDueToProviderChange = false;
1218 showVMDialog(msgId);
1219 updateVoiceNumberField();
1220 }
1221
1222 /**
1223 * Called when Voicemail Provider and its forwarding settings were successfully finished.
1224 * This updates a bunch of variables and show "success" dialog.
1225 */
1226 private void handleVMAndFwdSetSuccess(int msg) {
1227 if (DBG) {
1228 log("handleVMAndFwdSetSuccess(). current voicemail provider key: "
1229 + getCurrentVoicemailProviderKey());
1230 }
1231 mPreviousVMProviderKey = getCurrentVoicemailProviderKey();
1232 mChangingVMorFwdDueToProviderChange = false;
1233 showVMDialog(msg);
1234 updateVoiceNumberField();
1235 }
1236
1237 /**
1238 * Update the voicemail number from what we've recorded on the sim.
1239 */
1240 private void updateVoiceNumberField() {
1241 if (DBG) {
1242 log("updateVoiceNumberField(). mSubMenuVoicemailSettings=" + mSubMenuVoicemailSettings);
1243 }
1244 if (mSubMenuVoicemailSettings == null) {
1245 return;
1246 }
1247
1248 mOldVmNumber = mPhone.getVoiceMailNumber();
1249 if (mOldVmNumber == null) {
1250 mOldVmNumber = "";
1251 }
1252 mSubMenuVoicemailSettings.setPhoneNumber(mOldVmNumber);
1253 final String summary = (mOldVmNumber.length() > 0) ? mOldVmNumber :
1254 getString(R.string.voicemail_number_not_set);
1255 mSubMenuVoicemailSettings.setSummary(summary);
1256 }
1257
1258 /*
1259 * Helper Methods for Activity class.
1260 * The initial query commands are split into two pieces now
1261 * for individual expansion. This combined with the ability
1262 * to cancel queries allows for a much better user experience,
1263 * and also ensures that the user only waits to update the
1264 * data that is relevant.
1265 */
1266
1267 @Override
1268 protected void onPrepareDialog(int id, Dialog dialog) {
1269 super.onPrepareDialog(id, dialog);
1270 mCurrentDialogId = id;
1271 }
1272
1273 // dialog creation method, called by showDialog()
1274 @Override
1275 protected Dialog onCreateDialog(int id) {
1276 if ((id == VM_RESPONSE_ERROR) || (id == VM_NOCHANGE_ERROR) ||
1277 (id == FW_SET_RESPONSE_ERROR) || (id == FW_GET_RESPONSE_ERROR) ||
1278 (id == VOICEMAIL_DIALOG_CONFIRM)) {
1279
1280 AlertDialog.Builder b = new AlertDialog.Builder(this);
1281
1282 int msgId;
1283 int titleId = R.string.error_updating_title;
1284 switch (id) {
1285 case VOICEMAIL_DIALOG_CONFIRM:
1286 msgId = R.string.vm_changed;
1287 titleId = R.string.voicemail;
1288 // Set Button 2
1289 b.setNegativeButton(R.string.close_dialog, this);
1290 break;
1291 case VM_NOCHANGE_ERROR:
1292 // even though this is technically an error,
1293 // keep the title friendly.
1294 msgId = R.string.no_change;
1295 titleId = R.string.voicemail;
1296 // Set Button 2
1297 b.setNegativeButton(R.string.close_dialog, this);
1298 break;
1299 case VM_RESPONSE_ERROR:
1300 msgId = R.string.vm_change_failed;
1301 // Set Button 1
1302 b.setPositiveButton(R.string.close_dialog, this);
1303 break;
1304 case FW_SET_RESPONSE_ERROR:
1305 msgId = R.string.fw_change_failed;
1306 // Set Button 1
1307 b.setPositiveButton(R.string.close_dialog, this);
1308 break;
1309 case FW_GET_RESPONSE_ERROR:
1310 msgId = R.string.fw_get_in_vm_failed;
1311 b.setPositiveButton(R.string.alert_dialog_yes, this);
1312 b.setNegativeButton(R.string.alert_dialog_no, this);
1313 break;
1314 default:
1315 msgId = R.string.exception_error;
1316 // Set Button 3, tells the activity that the error is
1317 // not recoverable on dialog exit.
1318 b.setNeutralButton(R.string.close_dialog, this);
1319 break;
1320 }
1321
1322 b.setTitle(getText(titleId));
1323 String message = getText(msgId).toString();
1324 b.setMessage(message);
1325 b.setCancelable(false);
1326 AlertDialog dialog = b.create();
1327
1328 // make the dialog more obvious by bluring the background.
1329 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1330
1331 return dialog;
1332 } else if (id == VOICEMAIL_FWD_SAVING_DIALOG || id == VOICEMAIL_FWD_READING_DIALOG ||
1333 id == VOICEMAIL_REVERTING_DIALOG) {
1334 ProgressDialog dialog = new ProgressDialog(this);
1335 dialog.setTitle(getText(R.string.updating_title));
1336 dialog.setIndeterminate(true);
1337 dialog.setCancelable(false);
1338 dialog.setMessage(getText(
1339 id == VOICEMAIL_FWD_SAVING_DIALOG ? R.string.updating_settings :
1340 (id == VOICEMAIL_REVERTING_DIALOG ? R.string.reverting_settings :
1341 R.string.reading_settings)));
1342 return dialog;
1343 }
1344
1345
1346 return null;
1347 }
1348
1349 // This is a method implemented for DialogInterface.OnClickListener.
1350 // Used with the error dialog to close the app, voicemail dialog to just dismiss.
1351 // Close button is mapped to BUTTON_POSITIVE for the errors that close the activity,
1352 // while those that are mapped to BUTTON_NEUTRAL only move the preference focus.
1353 public void onClick(DialogInterface dialog, int which) {
1354 dialog.dismiss();
1355 switch (which){
1356 case DialogInterface.BUTTON_NEUTRAL:
1357 if (DBG) log("Neutral button");
1358 break;
1359 case DialogInterface.BUTTON_NEGATIVE:
1360 if (DBG) log("Negative button");
1361 if (mCurrentDialogId == FW_GET_RESPONSE_ERROR) {
1362 // We failed to get current forwarding settings and the user
1363 // does not wish to continue.
1364 switchToPreviousVoicemailProvider();
1365 }
1366 break;
1367 case DialogInterface.BUTTON_POSITIVE:
1368 if (DBG) log("Positive button");
1369 if (mCurrentDialogId == FW_GET_RESPONSE_ERROR) {
1370 // We failed to get current forwarding settings but the user
1371 // wishes to continue changing settings to the new vm provider
1372 saveVoiceMailAndForwardingNumberStage2();
1373 } else {
1374 finish();
1375 }
1376 return;
1377 default:
1378 // just let the dialog close and go back to the input
1379 }
1380 // In all dialogs, all buttons except BUTTON_POSITIVE lead to the end of user interaction
1381 // with settings UI. If we were called to explicitly configure voice mail then
1382 // we finish the settings activity here to come back to whatever the user was doing.
1383 if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) {
1384 finish();
1385 }
1386 }
1387
1388 // set the app state with optional status.
1389 private void showVMDialog(int msgStatus) {
1390 switch (msgStatus) {
1391 // It's a bit worrisome to punt in the error cases here when we're
1392 // not in the foreground; maybe toast instead?
1393 case MSG_VM_EXCEPTION:
1394 showDialogIfForeground(VM_RESPONSE_ERROR);
1395 break;
1396 case MSG_FW_SET_EXCEPTION:
1397 showDialogIfForeground(FW_SET_RESPONSE_ERROR);
1398 break;
1399 case MSG_FW_GET_EXCEPTION:
1400 showDialogIfForeground(FW_GET_RESPONSE_ERROR);
1401 break;
1402 case MSG_VM_NOCHANGE:
1403 showDialogIfForeground(VM_NOCHANGE_ERROR);
1404 break;
1405 case MSG_VM_OK:
1406 showDialogIfForeground(VOICEMAIL_DIALOG_CONFIRM);
1407 break;
1408 case MSG_OK:
1409 default:
1410 // This should never happen.
1411 }
1412 }
1413
1414 /*
1415 * Activity class methods
1416 */
1417
1418 @Override
1419 protected void onCreate(Bundle icicle) {
1420 super.onCreate(icicle);
1421 if (DBG) log("onCreate(). Intent: " + getIntent());
1422 mPhone = PhoneGlobals.getPhone();
Tyler Gunnbaee2952014-09-10 16:01:02 -07001423 mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1424
Tyler Gunnbaee2952014-09-10 16:01:02 -07001425 // Show the voicemail preference in onResume if the calling intent specifies the
1426 // ACTION_ADD_VOICEMAIL action.
1427 mShowVoicemailPreference = (icicle == null) &&
1428 getIntent().getAction().equals(ACTION_ADD_VOICEMAIL);
1429 }
1430
1431 private void initPhoneAccountPreferences() {
Andrew Leece8ae2a2014-09-10 10:41:48 -07001432 mPhoneAccountSettingsPreference = findPreference(PHONE_ACCOUNT_SETTINGS_KEY);
Tyler Gunnbaee2952014-09-10 16:01:02 -07001433
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001434 TelecomManager telecomManager = TelecomManager.from(this);
Andrew Lee93c345f2014-10-27 15:25:07 -07001435 TelephonyManager telephonyManager =
1436 (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Tyler Gunnbaee2952014-09-10 16:01:02 -07001437
Andrew Lee93c345f2014-10-27 15:25:07 -07001438 if ((telecomManager.getSimCallManagers().isEmpty() && !SipUtil.isVoipSupported(this))
1439 || telephonyManager.getPhoneCount() > 1) {
Andrew Leece8ae2a2014-09-10 10:41:48 -07001440 getPreferenceScreen().removePreference(mPhoneAccountSettingsPreference);
Tyler Gunnbaee2952014-09-10 16:01:02 -07001441 }
1442 }
1443
1444 private boolean canLaunchIntent(Intent intent) {
1445 PackageManager pm = getPackageManager();
1446 return pm.resolveActivity(intent, PackageManager.GET_ACTIVITIES) != null;
1447 }
1448
Tyler Gunnbaee2952014-09-10 16:01:02 -07001449 @Override
1450 protected void onResume() {
1451 super.onResume();
1452 mForeground = true;
1453
1454 PreferenceScreen preferenceScreen = getPreferenceScreen();
1455 if (preferenceScreen != null) {
1456 preferenceScreen.removeAll();
1457 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001458
1459 addPreferencesFromResource(R.xml.call_feature_setting);
Andrew Leedb2fe562014-09-03 15:40:43 -07001460 initPhoneAccountPreferences();
1461
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001462 PreferenceScreen prefSet = getPreferenceScreen();
Andrew Lee64a7d792014-10-15 17:38:38 -07001463 mSubMenuVoicemailSettings = (EditPhoneNumberPreference) findPreference(BUTTON_VOICEMAIL_KEY);
1464 mSubMenuVoicemailSettings.setParentActivity(this, VOICEMAIL_PREF_ID, this);
1465 mSubMenuVoicemailSettings.setDialogOnClosedListener(this);
1466 mSubMenuVoicemailSettings.setDialogTitle(R.string.voicemail_settings_number_label);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001467
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001468 mButtonDTMF = (ListPreference) findPreference(BUTTON_DTMF_KEY);
1469 mButtonAutoRetry = (CheckBoxPreference) findPreference(BUTTON_RETRY_KEY);
1470 mButtonHAC = (CheckBoxPreference) findPreference(BUTTON_HAC_KEY);
1471 mButtonTTY = (ListPreference) findPreference(BUTTON_TTY_KEY);
1472 mVoicemailProviders = (ListPreference) findPreference(BUTTON_VOICEMAIL_PROVIDER_KEY);
Andrew Lee312e8172014-10-23 17:01:36 -07001473 mEnableVideoCalling = (CheckBoxPreference) findPreference(ENABLE_VIDEO_CALLING_KEY);
Andrew Lee2170a972014-08-13 18:13:01 -07001474
Andrew Lee2c027892014-10-29 11:29:54 -07001475 mVoicemailProviders.setOnPreferenceChangeListener(this);
1476 mVoicemailSettingsScreen =
1477 (PreferenceScreen) findPreference(VOICEMAIL_SETTING_SCREEN_PREF_KEY);
1478 mVoicemailSettings = (PreferenceScreen)findPreference(BUTTON_VOICEMAIL_SETTING_KEY);
1479 mVoicemailNotificationVibrate =
1480 (CheckBoxPreference) findPreference(BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY);
1481 initVoiceMailProviders();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001482
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001483
Andrew Lee64a7d792014-10-15 17:38:38 -07001484 if (getResources().getBoolean(R.bool.dtmf_type_enabled)) {
1485 mButtonDTMF.setOnPreferenceChangeListener(this);
1486 int dtmf = Settings.System.getInt(getContentResolver(),
1487 Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, Constants.DTMF_TONE_TYPE_NORMAL);
1488 mButtonDTMF.setValueIndex(dtmf);
1489 } else {
1490 prefSet.removePreference(mButtonDTMF);
1491 mButtonDTMF = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001492 }
1493
Andrew Lee64a7d792014-10-15 17:38:38 -07001494 if (getResources().getBoolean(R.bool.auto_retry_enabled)) {
1495 mButtonAutoRetry.setOnPreferenceChangeListener(this);
1496 int autoretry = Settings.Global.getInt(
1497 getContentResolver(), Settings.Global.CALL_AUTO_RETRY, 0);
1498 mButtonAutoRetry.setChecked(autoretry != 0);
1499 } else {
1500 prefSet.removePreference(mButtonAutoRetry);
1501 mButtonAutoRetry = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001502 }
1503
Andrew Lee64a7d792014-10-15 17:38:38 -07001504 if (getResources().getBoolean(R.bool.hac_enabled)) {
1505 mButtonHAC.setOnPreferenceChangeListener(this);
1506 int hac = Settings.System.getInt(getContentResolver(), Settings.System.HEARING_AID, 0);
1507 mButtonHAC.setChecked(hac != 0);
1508 } else {
1509 prefSet.removePreference(mButtonHAC);
1510 mButtonHAC = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001511 }
1512
Andrew Lee64a7d792014-10-15 17:38:38 -07001513 TelecomManager telecomManager = TelecomManager.from(this);
1514 if (telecomManager != null && telecomManager.isTtySupported()) {
1515 mButtonTTY.setOnPreferenceChangeListener(this);
1516 int settingsTtyMode = Settings.Secure.getInt(getContentResolver(),
1517 Settings.Secure.PREFERRED_TTY_MODE,
1518 TelecomManager.TTY_MODE_OFF);
1519 mButtonTTY.setValue(Integer.toString(settingsTtyMode));
1520 updatePreferredTtyModeSummary(settingsTtyMode);
1521 } else {
1522 prefSet.removePreference(mButtonTTY);
1523 mButtonTTY = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001524 }
1525
1526 if (!getResources().getBoolean(R.bool.world_phone)) {
1527 Preference options = prefSet.findPreference(BUTTON_CDMA_OPTIONS);
Andrew Lee2170a972014-08-13 18:13:01 -07001528 if (options != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001529 prefSet.removePreference(options);
Andrew Lee2170a972014-08-13 18:13:01 -07001530 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001531 options = prefSet.findPreference(BUTTON_GSM_UMTS_OPTIONS);
Andrew Lee2170a972014-08-13 18:13:01 -07001532 if (options != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001533 prefSet.removePreference(options);
Andrew Lee2170a972014-08-13 18:13:01 -07001534 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001535
1536 int phoneType = mPhone.getPhoneType();
1537 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
1538 Preference fdnButton = prefSet.findPreference(BUTTON_FDN_KEY);
Andrew Lee2170a972014-08-13 18:13:01 -07001539 if (fdnButton != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001540 prefSet.removePreference(fdnButton);
Andrew Lee2170a972014-08-13 18:13:01 -07001541 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001542 if (!getResources().getBoolean(R.bool.config_voice_privacy_disable)) {
1543 addPreferencesFromResource(R.xml.cdma_call_privacy);
1544 }
1545 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
Andrew Lee2170a972014-08-13 18:13:01 -07001546 if (getResources().getBoolean(R.bool.config_additional_call_setting)) {
Etan Cohen0ca1c802014-07-07 15:35:48 -07001547 addPreferencesFromResource(R.xml.gsm_umts_call_options);
1548 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001549 } else {
1550 throw new IllegalStateException("Unexpected phone type: " + phoneType);
1551 }
1552 }
1553
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001554 // check the intent that started this activity and pop up the voicemail
1555 // dialog if we've been asked to.
1556 // If we have at least one non default VM provider registered then bring up
1557 // the selection for the VM provider, otherwise bring up a VM number dialog.
1558 // We only bring up the dialog the first time we are called (not after orientation change)
Andrew Lee2c027892014-10-29 11:29:54 -07001559 if (mShowVoicemailPreference) {
Tyler Gunnbaee2952014-09-10 16:01:02 -07001560 if (DBG) {
1561 log("ACTION_ADD_VOICEMAIL Intent is thrown. current VM data size: "
1562 + mVMProvidersData.size());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001563 }
Tyler Gunnbaee2952014-09-10 16:01:02 -07001564 if (mVMProvidersData.size() > 1) {
1565 simulatePreferenceClick(mVoicemailProviders);
1566 } else {
1567 onPreferenceChange(mVoicemailProviders, DEFAULT_VM_PROVIDER_KEY);
1568 mVoicemailProviders.setValue(DEFAULT_VM_PROVIDER_KEY);
1569 }
1570 mShowVoicemailPreference = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001571 }
Tyler Gunnbaee2952014-09-10 16:01:02 -07001572
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001573 updateVoiceNumberField();
1574 mVMProviderSettingsForced = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001575
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001576 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
1577 mPhone.getContext());
1578 if (migrateVoicemailVibrationSettingsIfNeeded(prefs)) {
1579 mVoicemailNotificationVibrate.setChecked(prefs.getBoolean(
1580 BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY, false));
1581 }
1582
Andrew Lee312e8172014-10-23 17:01:36 -07001583 if (ImsManager.isVtEnabledByPlatform(mPhone.getContext()) && ENABLE_VT_FLAG) {
1584 boolean currentValue =
1585 ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())
1586 ? PhoneGlobals.getInstance().phoneMgr.isVideoCallingEnabled() : false;
1587 mEnableVideoCalling.setChecked(currentValue);
Andrew Lee77527ac2014-10-21 16:57:39 -07001588 mEnableVideoCalling.setOnPreferenceChangeListener(this);
1589 } else {
1590 prefSet.removePreference(mEnableVideoCalling);
1591 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001592 }
1593
1594 // Migrate settings from BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_WHEN_KEY to
1595 // BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY, if the latter does not exist.
1596 // Returns true if migration was performed.
1597 public static boolean migrateVoicemailVibrationSettingsIfNeeded(SharedPreferences prefs) {
1598 if (!prefs.contains(BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY)) {
1599 String vibrateWhen = prefs.getString(
1600 BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_WHEN_KEY, VOICEMAIL_VIBRATION_NEVER);
1601 // If vibrateWhen is always, then voicemailVibrate should be True.
1602 // otherwise if vibrateWhen is "only in silent mode", or "never", then
1603 // voicemailVibrate = False.
1604 boolean voicemailVibrate = vibrateWhen.equals(VOICEMAIL_VIBRATION_ALWAYS);
1605 final SharedPreferences.Editor editor = prefs.edit();
1606 editor.putBoolean(BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY, voicemailVibrate);
1607 editor.commit();
1608 return true;
1609 }
1610 return false;
1611 }
1612
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001613 private void handleTTYChange(Preference preference, Object objValue) {
1614 int buttonTtyMode;
1615 buttonTtyMode = Integer.valueOf((String) objValue).intValue();
1616 int settingsTtyMode = android.provider.Settings.Secure.getInt(
1617 getContentResolver(),
Sailesh Nepalbf900542014-07-15 16:18:32 -07001618 android.provider.Settings.Secure.PREFERRED_TTY_MODE,
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001619 TelecomManager.TTY_MODE_OFF);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001620 if (DBG) log("handleTTYChange: requesting set TTY mode enable (TTY) to" +
1621 Integer.toString(buttonTtyMode));
1622
1623 if (buttonTtyMode != settingsTtyMode) {
1624 switch(buttonTtyMode) {
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001625 case TelecomManager.TTY_MODE_OFF:
1626 case TelecomManager.TTY_MODE_FULL:
1627 case TelecomManager.TTY_MODE_HCO:
1628 case TelecomManager.TTY_MODE_VCO:
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001629 android.provider.Settings.Secure.putInt(getContentResolver(),
1630 android.provider.Settings.Secure.PREFERRED_TTY_MODE, buttonTtyMode);
1631 break;
1632 default:
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001633 buttonTtyMode = TelecomManager.TTY_MODE_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001634 }
1635
1636 mButtonTTY.setValue(Integer.toString(buttonTtyMode));
1637 updatePreferredTtyModeSummary(buttonTtyMode);
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001638 Intent ttyModeChanged = new Intent(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
1639 ttyModeChanged.putExtra(TelecomManager.EXTRA_TTY_PREFERRED_MODE, buttonTtyMode);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001640 sendBroadcastAsUser(ttyModeChanged, UserHandle.ALL);
1641 }
1642 }
1643
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001644 private void updatePreferredTtyModeSummary(int TtyMode) {
1645 String [] txts = getResources().getStringArray(R.array.tty_mode_entries);
1646 switch(TtyMode) {
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001647 case TelecomManager.TTY_MODE_OFF:
1648 case TelecomManager.TTY_MODE_HCO:
1649 case TelecomManager.TTY_MODE_VCO:
1650 case TelecomManager.TTY_MODE_FULL:
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001651 mButtonTTY.setSummary(txts[TtyMode]);
1652 break;
1653 default:
1654 mButtonTTY.setEnabled(false);
Tyler Gunn4d45d1c2014-09-12 22:17:53 -07001655 mButtonTTY.setSummary(txts[TelecomManager.TTY_MODE_OFF]);
Sailesh Nepalbf900542014-07-15 16:18:32 -07001656 break;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001657 }
1658 }
1659
1660 private static void log(String msg) {
1661 Log.d(LOG_TAG, msg);
1662 }
1663
1664 /**
1665 * Updates the look of the VM preference widgets based on current VM provider settings.
1666 * Note that the provider name is loaded form the found activity via loadLabel in
1667 * {@link #initVoiceMailProviders()} in order for it to be localizable.
1668 */
1669 private void updateVMPreferenceWidgets(String currentProviderSetting) {
1670 final String key = currentProviderSetting;
1671 final VoiceMailProvider provider = mVMProvidersData.get(key);
1672
1673 /* This is the case when we are coming up on a freshly wiped phone and there is no
1674 persisted value for the list preference mVoicemailProviders.
1675 In this case we want to show the UI asking the user to select a voicemail provider as
1676 opposed to silently falling back to default one. */
1677 if (provider == null) {
1678 if (DBG) {
1679 log("updateVMPreferenceWidget: provider for the key \"" + key + "\" is null.");
1680 }
1681 mVoicemailProviders.setSummary(getString(R.string.sum_voicemail_choose_provider));
1682 mVoicemailSettings.setEnabled(false);
1683 mVoicemailSettings.setIntent(null);
1684
1685 mVoicemailNotificationVibrate.setEnabled(false);
1686 } else {
1687 if (DBG) {
1688 log("updateVMPreferenceWidget: provider for the key \"" + key + "\".."
1689 + "name: " + provider.name
1690 + ", intent: " + provider.intent);
1691 }
1692 final String providerName = provider.name;
1693 mVoicemailProviders.setSummary(providerName);
1694 mVoicemailSettings.setEnabled(true);
1695 mVoicemailSettings.setIntent(provider.intent);
1696
1697 mVoicemailNotificationVibrate.setEnabled(true);
1698 }
1699 }
1700
1701 /**
1702 * Enumerates existing VM providers and puts their data into the list and populates
1703 * the preference list objects with their names.
1704 * In case we are called with ACTION_ADD_VOICEMAIL intent the intent may have
1705 * an extra string called IGNORE_PROVIDER_EXTRA with "package.activityName" of the provider
1706 * which should be hidden when we bring up the list of possible VM providers to choose.
1707 */
1708 private void initVoiceMailProviders() {
1709 if (DBG) log("initVoiceMailProviders()");
1710 mPerProviderSavedVMNumbers =
1711 this.getApplicationContext().getSharedPreferences(
1712 VM_NUMBERS_SHARED_PREFERENCES_NAME, MODE_PRIVATE);
1713
1714 String providerToIgnore = null;
1715 if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) {
1716 if (getIntent().hasExtra(IGNORE_PROVIDER_EXTRA)) {
1717 providerToIgnore = getIntent().getStringExtra(IGNORE_PROVIDER_EXTRA);
1718 }
1719 if (DBG) log("Found ACTION_ADD_VOICEMAIL. providerToIgnore=" + providerToIgnore);
1720 if (providerToIgnore != null) {
1721 // IGNORE_PROVIDER_EXTRA implies we want to remove the choice from the list.
1722 deleteSettingsForVoicemailProvider(providerToIgnore);
1723 }
1724 }
1725
1726 mVMProvidersData.clear();
1727
1728 // Stick the default element which is always there
1729 final String myCarrier = getString(R.string.voicemail_default);
1730 mVMProvidersData.put(DEFAULT_VM_PROVIDER_KEY, new VoiceMailProvider(myCarrier, null));
1731
1732 // Enumerate providers
1733 PackageManager pm = getPackageManager();
1734 Intent intent = new Intent();
1735 intent.setAction(ACTION_CONFIGURE_VOICEMAIL);
1736 List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
1737 int len = resolveInfos.size() + 1; // +1 for the default choice we will insert.
1738
1739 // Go through the list of discovered providers populating the data map
1740 // skip the provider we were instructed to ignore if there was one
1741 for (int i = 0; i < resolveInfos.size(); i++) {
1742 final ResolveInfo ri= resolveInfos.get(i);
1743 final ActivityInfo currentActivityInfo = ri.activityInfo;
1744 final String key = makeKeyForActivity(currentActivityInfo);
1745 if (key.equals(providerToIgnore)) {
1746 if (DBG) log("Ignoring key: " + key);
1747 len--;
1748 continue;
1749 }
1750 if (DBG) log("Loading key: " + key);
1751 final String nameForDisplay = ri.loadLabel(pm).toString();
1752 Intent providerIntent = new Intent();
1753 providerIntent.setAction(ACTION_CONFIGURE_VOICEMAIL);
1754 providerIntent.setClassName(currentActivityInfo.packageName,
1755 currentActivityInfo.name);
1756 if (DBG) {
1757 log("Store loaded VoiceMailProvider. key: " + key
1758 + " -> name: " + nameForDisplay + ", intent: " + providerIntent);
1759 }
1760 mVMProvidersData.put(
1761 key,
1762 new VoiceMailProvider(nameForDisplay, providerIntent));
1763
1764 }
1765
1766 // Now we know which providers to display - create entries and values array for
1767 // the list preference
1768 String [] entries = new String [len];
1769 String [] values = new String [len];
1770 entries[0] = myCarrier;
1771 values[0] = DEFAULT_VM_PROVIDER_KEY;
1772 int entryIdx = 1;
1773 for (int i = 0; i < resolveInfos.size(); i++) {
1774 final String key = makeKeyForActivity(resolveInfos.get(i).activityInfo);
1775 if (!mVMProvidersData.containsKey(key)) {
1776 continue;
1777 }
1778 entries[entryIdx] = mVMProvidersData.get(key).name;
1779 values[entryIdx] = key;
1780 entryIdx++;
1781 }
1782
1783 // ListPreference is now updated.
1784 mVoicemailProviders.setEntries(entries);
1785 mVoicemailProviders.setEntryValues(values);
1786
1787 // Remember the current Voicemail Provider key as a "previous" key. This will be used
1788 // when we fail to update Voicemail Provider, which requires rollback.
1789 // We will update this when the VM Provider setting is successfully updated.
1790 mPreviousVMProviderKey = getCurrentVoicemailProviderKey();
1791 if (DBG) log("Set up the first mPreviousVMProviderKey: " + mPreviousVMProviderKey);
1792
1793 // Finally update the preference texts.
1794 updateVMPreferenceWidgets(mPreviousVMProviderKey);
1795 }
1796
1797 private String makeKeyForActivity(ActivityInfo ai) {
1798 return ai.name;
1799 }
1800
1801 /**
1802 * Simulates user clicking on a passed preference.
1803 * Usually needed when the preference is a dialog preference and we want to invoke
1804 * a dialog for this preference programmatically.
Santos Cordonda120f42014-08-06 04:44:34 -07001805 * TODO: figure out if there is a cleaner way to cause preference dlg to come up
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001806 */
1807 private void simulatePreferenceClick(Preference preference) {
1808 // Go through settings until we find our setting
1809 // and then simulate a click on it to bring up the dialog
1810 final ListAdapter adapter = getPreferenceScreen().getRootAdapter();
1811 for (int idx = 0; idx < adapter.getCount(); idx++) {
1812 if (adapter.getItem(idx) == preference) {
1813 getPreferenceScreen().onItemClick(this.getListView(),
1814 null, idx, adapter.getItemId(idx));
1815 break;
1816 }
1817 }
1818 }
1819
1820 /**
1821 * Saves new VM provider settings associating them with the currently selected
1822 * provider if settings are different than the ones already stored for this
1823 * provider.
1824 * Later on these will be used when the user switches a provider.
1825 */
1826 private void maybeSaveSettingsForVoicemailProvider(String key,
Andrew Leeb490d732014-10-27 15:00:41 -07001827 VoicemailProviderSettings newSettings) {
Andrew Leeb490d732014-10-27 15:00:41 -07001828 final VoicemailProviderSettings curSettings = loadSettingsForVoiceMailProvider(key);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001829 if (newSettings.equals(curSettings)) {
1830 if (DBG) {
1831 log("maybeSaveSettingsForVoicemailProvider:"
1832 + " Not saving setting for " + key + " since they have not changed");
1833 }
1834 return;
1835 }
1836 if (DBG) log("Saving settings for " + key + ": " + newSettings.toString());
1837 Editor editor = mPerProviderSavedVMNumbers.edit();
Andrew Leeb490d732014-10-27 15:00:41 -07001838 editor.putString(key + VM_NUMBER_TAG, newSettings.getVoicemailNumber());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001839 String fwdKey = key + FWD_SETTINGS_TAG;
Andrew Leeb490d732014-10-27 15:00:41 -07001840 CallForwardInfo[] s = newSettings.getForwardingSettings();
1841 if (s != VoicemailProviderSettings.NO_FORWARDING) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001842 editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, s.length);
1843 for (int i = 0; i < s.length; i++) {
1844 final String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i);
1845 final CallForwardInfo fi = s[i];
1846 editor.putInt(settingKey + FWD_SETTING_STATUS, fi.status);
1847 editor.putInt(settingKey + FWD_SETTING_REASON, fi.reason);
1848 editor.putString(settingKey + FWD_SETTING_NUMBER, fi.number);
1849 editor.putInt(settingKey + FWD_SETTING_TIME, fi.timeSeconds);
1850 }
1851 } else {
1852 editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0);
1853 }
1854 editor.apply();
1855 }
1856
1857 /**
1858 * Returns settings previously stored for the currently selected
1859 * voice mail provider. If none is stored returns null.
1860 * If the user switches to a voice mail provider and we have settings
1861 * stored for it we will automatically change the phone's voice mail number
1862 * and forwarding number to the stored one. Otherwise we will bring up provider's configuration
1863 * UI.
1864 */
Andrew Leeb490d732014-10-27 15:00:41 -07001865 private VoicemailProviderSettings loadSettingsForVoiceMailProvider(String key) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001866 final String vmNumberSetting = mPerProviderSavedVMNumbers.getString(key + VM_NUMBER_TAG,
1867 null);
1868 if (vmNumberSetting == null) {
1869 Log.w(LOG_TAG, "VoiceMailProvider settings for the key \"" + key + "\""
1870 + " was not found. Returning null.");
1871 return null;
1872 }
1873
Andrew Leeb490d732014-10-27 15:00:41 -07001874 CallForwardInfo[] cfi = VoicemailProviderSettings.NO_FORWARDING;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001875 String fwdKey = key + FWD_SETTINGS_TAG;
1876 final int fwdLen = mPerProviderSavedVMNumbers.getInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0);
1877 if (fwdLen > 0) {
1878 cfi = new CallForwardInfo[fwdLen];
1879 for (int i = 0; i < cfi.length; i++) {
1880 final String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i);
1881 cfi[i] = new CallForwardInfo();
1882 cfi[i].status = mPerProviderSavedVMNumbers.getInt(
1883 settingKey + FWD_SETTING_STATUS, 0);
1884 cfi[i].reason = mPerProviderSavedVMNumbers.getInt(
1885 settingKey + FWD_SETTING_REASON,
1886 CommandsInterface.CF_REASON_ALL_CONDITIONAL);
1887 cfi[i].serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
1888 cfi[i].toa = PhoneNumberUtils.TOA_International;
1889 cfi[i].number = mPerProviderSavedVMNumbers.getString(
1890 settingKey + FWD_SETTING_NUMBER, "");
1891 cfi[i].timeSeconds = mPerProviderSavedVMNumbers.getInt(
1892 settingKey + FWD_SETTING_TIME, 20);
1893 }
1894 }
1895
Andrew Leeb490d732014-10-27 15:00:41 -07001896 VoicemailProviderSettings settings = new VoicemailProviderSettings(vmNumberSetting, cfi);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001897 if (DBG) log("Loaded settings for " + key + ": " + settings.toString());
1898 return settings;
1899 }
1900
1901 /**
1902 * Deletes settings for the specified provider.
1903 */
1904 private void deleteSettingsForVoicemailProvider(String key) {
1905 if (DBG) log("Deleting settings for" + key);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001906 mPerProviderSavedVMNumbers.edit()
1907 .putString(key + VM_NUMBER_TAG, null)
1908 .putInt(key + FWD_SETTINGS_TAG + FWD_SETTINGS_LENGTH_TAG, 0)
1909 .commit();
1910 }
1911
1912 private String getCurrentVoicemailProviderKey() {
1913 final String key = mVoicemailProviders.getValue();
1914 return (key != null) ? key : DEFAULT_VM_PROVIDER_KEY;
1915 }
1916
1917 @Override
1918 public boolean onOptionsItemSelected(MenuItem item) {
1919 final int itemId = item.getItemId();
1920 if (itemId == android.R.id.home) { // See ActionBar#setDisplayHomeAsUpEnabled()
Yorke Leef2d0cac2013-09-09 19:42:56 -07001921 onBackPressed();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001922 return true;
1923 }
1924 return super.onOptionsItemSelected(item);
1925 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001926 /**
1927 * Finish current Activity and go up to the top level Settings ({@link CallFeaturesSetting}).
1928 * This is useful for implementing "HomeAsUp" capability for second-level Settings.
1929 */
1930 public static void goUpToTopLevelSetting(Activity activity) {
1931 Intent intent = new Intent(activity, CallFeaturesSetting.class);
1932 intent.setAction(Intent.ACTION_MAIN);
1933 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1934 activity.startActivity(intent);
1935 activity.finish();
1936 }
1937}