1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.phone; 18 19 import android.app.ActionBar; 20 import android.app.Activity; 21 import android.app.ActivityOptions; 22 import android.app.AlertDialog; 23 import android.app.Dialog; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.DialogInterface; 27 import android.content.Intent; 28 import android.content.pm.ApplicationInfo; 29 import android.content.pm.PackageManager; 30 import android.content.pm.PackageManager.NameNotFoundException; 31 import android.content.pm.ResolveInfo; 32 import android.os.Bundle; 33 import android.os.PersistableBundle; 34 import android.os.UserHandle; 35 import android.os.UserManager; 36 import android.preference.ListPreference; 37 import android.preference.Preference; 38 import android.preference.PreferenceActivity; 39 import android.preference.PreferenceScreen; 40 import android.preference.SwitchPreference; 41 import android.provider.Settings; 42 import android.telecom.PhoneAccountHandle; 43 import android.telecom.TelecomManager; 44 import android.telephony.CarrierConfigManager; 45 import android.telephony.PhoneStateListener; 46 import android.telephony.TelephonyManager; 47 import android.text.TextUtils; 48 import android.util.Log; 49 import android.view.MenuItem; 50 import android.widget.Toast; 51 52 import com.android.ims.ImsConfig; 53 import com.android.ims.ImsManager; 54 import com.android.internal.telephony.CallForwardInfo; 55 import com.android.internal.telephony.Phone; 56 import com.android.internal.telephony.PhoneConstants; 57 import com.android.phone.common.util.SettingsUtil; 58 import com.android.phone.settings.AccountSelectionPreference; 59 import com.android.phone.settings.PhoneAccountSettingsFragment; 60 import com.android.phone.settings.VoicemailSettingsActivity; 61 import com.android.phone.settings.fdn.FdnSetting; 62 import com.android.services.telephony.sip.SipUtil; 63 64 import java.lang.String; 65 import java.util.ArrayList; 66 import java.util.List; 67 68 /** 69 * Top level "Call settings" UI; see res/xml/call_feature_setting.xml 70 * 71 * This preference screen is the root of the "Call settings" hierarchy available from the Phone 72 * app; the settings here let you control various features related to phone calls (including 73 * voicemail settings, the "Respond via SMS" feature, and others.) It's used only on 74 * voice-capable phone devices. 75 * 76 * Note that this activity is part of the package com.android.phone, even 77 * though you reach it from the "Phone" app (i.e. DialtactsActivity) which 78 * is from the package com.android.contacts. 79 * 80 * For the "Mobile network settings" screen under the main Settings app, 81 * See {@link MobileNetworkSettings}. 82 * 83 * @see com.android.phone.MobileNetworkSettings 84 */ 85 public class CallFeaturesSetting extends PreferenceActivity 86 implements Preference.OnPreferenceChangeListener { 87 private static final String LOG_TAG = "CallFeaturesSetting"; 88 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2); 89 90 // String keys for preference lookup 91 // TODO: Naming these "BUTTON_*" is confusing since they're not actually buttons(!) 92 // TODO: Consider moving these strings to strings.xml, so that they are not duplicated here and 93 // in the layout files. These strings need to be treated carefully; if the setting is 94 // persistent, they are used as the key to store shared preferences and the name should not be 95 // changed unless the settings are also migrated. 96 private static final String VOICEMAIL_SETTING_SCREEN_PREF_KEY = "button_voicemail_category_key"; 97 private static final String BUTTON_FDN_KEY = "button_fdn_key"; 98 private static final String BUTTON_RETRY_KEY = "button_auto_retry_key"; 99 private static final String BUTTON_GSM_UMTS_OPTIONS = "button_gsm_more_expand_key"; 100 private static final String BUTTON_CDMA_OPTIONS = "button_cdma_more_expand_key"; 101 102 private static final String PHONE_ACCOUNT_SETTINGS_KEY = 103 "phone_account_settings_preference_screen"; 104 105 private static final String ENABLE_VIDEO_CALLING_KEY = "button_enable_video_calling"; 106 107 private Phone mPhone; 108 private SubscriptionInfoHelper mSubscriptionInfoHelper; 109 private TelecomManager mTelecomManager; 110 111 private SwitchPreference mButtonAutoRetry; 112 private PreferenceScreen mVoicemailSettingsScreen; 113 private SwitchPreference mEnableVideoCalling; 114 115 /* 116 * Click Listeners, handle click based on objects attached to UI. 117 */ 118 119 // Click listener for all toggle events 120 @Override onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)121 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 122 if (preference == mButtonAutoRetry) { 123 android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(), 124 android.provider.Settings.Global.CALL_AUTO_RETRY, 125 mButtonAutoRetry.isChecked() ? 1 : 0); 126 return true; 127 } 128 return false; 129 } 130 131 /** 132 * Implemented to support onPreferenceChangeListener to look for preference 133 * changes. 134 * 135 * @param preference is the preference to be changed 136 * @param objValue should be the value of the selection, NOT its localized 137 * display value. 138 */ 139 @Override onPreferenceChange(Preference preference, Object objValue)140 public boolean onPreferenceChange(Preference preference, Object objValue) { 141 if (DBG) log("onPreferenceChange: \"" + preference + "\" changed to \"" + objValue + "\""); 142 143 if (preference == mEnableVideoCalling) { 144 if (ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())) { 145 PhoneGlobals.getInstance().phoneMgr.enableVideoCalling((boolean) objValue); 146 } else { 147 AlertDialog.Builder builder = new AlertDialog.Builder(this); 148 DialogInterface.OnClickListener networkSettingsClickListener = 149 new Dialog.OnClickListener() { 150 @Override 151 public void onClick(DialogInterface dialog, int which) { 152 startActivity(new Intent(mPhone.getContext(), 153 com.android.phone.MobileNetworkSettings.class)); 154 } 155 }; 156 builder.setMessage(getResources().getString( 157 R.string.enable_video_calling_dialog_msg)) 158 .setNeutralButton(getResources().getString( 159 R.string.enable_video_calling_dialog_settings), 160 networkSettingsClickListener) 161 .setPositiveButton(android.R.string.ok, null) 162 .show(); 163 return false; 164 } 165 } 166 167 // Always let the preference setting proceed. 168 return true; 169 } 170 171 @Override onCreate(Bundle icicle)172 protected void onCreate(Bundle icicle) { 173 super.onCreate(icicle); 174 if (DBG) log("onCreate: Intent is " + getIntent()); 175 176 // Make sure we are running as an admin user. 177 if (!UserManager.get(this).isAdminUser()) { 178 Toast.makeText(this, R.string.call_settings_admin_user_only, 179 Toast.LENGTH_SHORT).show(); 180 finish(); 181 return; 182 } 183 184 mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, getIntent()); 185 mSubscriptionInfoHelper.setActionBarTitle( 186 getActionBar(), getResources(), R.string.call_settings_with_label); 187 mPhone = mSubscriptionInfoHelper.getPhone(); 188 mTelecomManager = TelecomManager.from(this); 189 } 190 191 private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 192 @Override 193 public void onCallStateChanged(int state, String incomingNumber) { 194 if (DBG) log("PhoneStateListener onCallStateChanged: state is " + state); 195 if (mEnableVideoCalling != null) { 196 mEnableVideoCalling.setEnabled(state == TelephonyManager.CALL_STATE_IDLE); 197 } 198 } 199 }; 200 201 @Override onPause()202 protected void onPause() { 203 super.onPause(); 204 TelephonyManager telephonyManager = 205 (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 206 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); 207 } 208 209 @Override onResume()210 protected void onResume() { 211 super.onResume(); 212 213 PreferenceScreen preferenceScreen = getPreferenceScreen(); 214 if (preferenceScreen != null) { 215 preferenceScreen.removeAll(); 216 } 217 218 addPreferencesFromResource(R.xml.call_feature_setting); 219 220 TelephonyManager telephonyManager = 221 (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 222 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 223 224 Preference phoneAccountSettingsPreference = findPreference(PHONE_ACCOUNT_SETTINGS_KEY); 225 if (telephonyManager.isMultiSimEnabled() || !SipUtil.isVoipSupported(mPhone.getContext())) { 226 getPreferenceScreen().removePreference(phoneAccountSettingsPreference); 227 } 228 229 PreferenceScreen prefSet = getPreferenceScreen(); 230 mVoicemailSettingsScreen = 231 (PreferenceScreen) findPreference(VOICEMAIL_SETTING_SCREEN_PREF_KEY); 232 mVoicemailSettingsScreen.setIntent(mSubscriptionInfoHelper.getIntent( 233 VoicemailSettingsActivity.class)); 234 235 maybeHideVoicemailSettings(); 236 237 mButtonAutoRetry = (SwitchPreference) findPreference(BUTTON_RETRY_KEY); 238 239 mEnableVideoCalling = (SwitchPreference) findPreference(ENABLE_VIDEO_CALLING_KEY); 240 241 PersistableBundle carrierConfig = 242 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 243 244 if (carrierConfig.getBoolean(CarrierConfigManager.KEY_AUTO_RETRY_ENABLED_BOOL)) { 245 mButtonAutoRetry.setOnPreferenceChangeListener(this); 246 int autoretry = Settings.Global.getInt( 247 getContentResolver(), Settings.Global.CALL_AUTO_RETRY, 0); 248 mButtonAutoRetry.setChecked(autoretry != 0); 249 } else { 250 prefSet.removePreference(mButtonAutoRetry); 251 mButtonAutoRetry = null; 252 } 253 254 Preference cdmaOptions = prefSet.findPreference(BUTTON_CDMA_OPTIONS); 255 Preference gsmOptions = prefSet.findPreference(BUTTON_GSM_UMTS_OPTIONS); 256 Preference fdnButton = prefSet.findPreference(BUTTON_FDN_KEY); 257 fdnButton.setIntent(mSubscriptionInfoHelper.getIntent(FdnSetting.class)); 258 if (carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { 259 cdmaOptions.setIntent(mSubscriptionInfoHelper.getIntent(CdmaCallOptions.class)); 260 gsmOptions.setIntent(mSubscriptionInfoHelper.getIntent(GsmUmtsCallOptions.class)); 261 } else { 262 prefSet.removePreference(cdmaOptions); 263 prefSet.removePreference(gsmOptions); 264 265 int phoneType = mPhone.getPhoneType(); 266 if (carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)) { 267 prefSet.removePreference(fdnButton); 268 } else { 269 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { 270 prefSet.removePreference(fdnButton); 271 272 if (!carrierConfig.getBoolean( 273 CarrierConfigManager.KEY_VOICE_PRIVACY_DISABLE_UI_BOOL)) { 274 addPreferencesFromResource(R.xml.cdma_call_privacy); 275 } 276 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { 277 278 if (carrierConfig.getBoolean( 279 CarrierConfigManager.KEY_ADDITIONAL_CALL_SETTING_BOOL)) { 280 addPreferencesFromResource(R.xml.gsm_umts_call_options); 281 GsmUmtsCallOptions.init(prefSet, mSubscriptionInfoHelper); 282 } 283 } else { 284 throw new IllegalStateException("Unexpected phone type: " + phoneType); 285 } 286 } 287 } 288 289 if (ImsManager.isVtEnabledByPlatform(mPhone.getContext()) && 290 ImsManager.isVtProvisionedOnDevice(mPhone.getContext()) && 291 (carrierConfig.getBoolean( 292 CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS) 293 || mPhone.mDcTracker.isDataEnabled())) { 294 boolean currentValue = 295 ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext()) 296 ? PhoneGlobals.getInstance().phoneMgr.isVideoCallingEnabled( 297 getOpPackageName()) : false; 298 mEnableVideoCalling.setChecked(currentValue); 299 mEnableVideoCalling.setOnPreferenceChangeListener(this); 300 } else { 301 prefSet.removePreference(mEnableVideoCalling); 302 } 303 304 if (ImsManager.isVolteEnabledByPlatform(this) && 305 !carrierConfig.getBoolean( 306 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) { 307 TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 308 /* tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); */ 309 } 310 311 Preference wifiCallingSettings = findPreference( 312 getResources().getString(R.string.wifi_calling_settings_key)); 313 314 final PhoneAccountHandle simCallManager = mTelecomManager.getSimCallManager(); 315 if (simCallManager != null) { 316 Intent intent = PhoneAccountSettingsFragment.buildPhoneAccountConfigureIntent( 317 this, simCallManager); 318 if (intent != null) { 319 PackageManager pm = mPhone.getContext().getPackageManager(); 320 List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0); 321 if (!resolutions.isEmpty()) { 322 wifiCallingSettings.setTitle(resolutions.get(0).loadLabel(pm)); 323 wifiCallingSettings.setSummary(null); 324 wifiCallingSettings.setIntent(intent); 325 } else { 326 prefSet.removePreference(wifiCallingSettings); 327 } 328 } else { 329 prefSet.removePreference(wifiCallingSettings); 330 } 331 } else if (!ImsManager.isWfcEnabledByPlatform(mPhone.getContext()) || 332 !ImsManager.isWfcProvisionedOnDevice(mPhone.getContext())) { 333 prefSet.removePreference(wifiCallingSettings); 334 } else { 335 int resId = com.android.internal.R.string.wifi_calling_off_summary; 336 if (ImsManager.isWfcEnabledByUser(mPhone.getContext())) { 337 boolean isRoaming = telephonyManager.isNetworkRoaming(); 338 int wfcMode = ImsManager.getWfcMode(mPhone.getContext(), isRoaming); 339 switch (wfcMode) { 340 case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY: 341 resId = com.android.internal.R.string.wfc_mode_wifi_only_summary; 342 break; 343 case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED: 344 resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary; 345 break; 346 case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED: 347 resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary; 348 break; 349 default: 350 if (DBG) log("Unexpected WFC mode value: " + wfcMode); 351 } 352 } 353 wifiCallingSettings.setSummary(resId); 354 } 355 } 356 357 /** 358 * Hides the top level voicemail settings entry point if the default dialer contains a 359 * particular manifest metadata key. This is required when the default dialer wants to display 360 * its own version of voicemail settings. 361 */ maybeHideVoicemailSettings()362 private void maybeHideVoicemailSettings() { 363 String defaultDialer = getSystemService(TelecomManager.class).getDefaultDialerPackage(); 364 if (defaultDialer == null) { 365 return; 366 } 367 try { 368 Bundle metadata = getPackageManager() 369 .getApplicationInfo(defaultDialer, PackageManager.GET_META_DATA).metaData; 370 if (metadata == null) { 371 return; 372 } 373 if (!metadata 374 .getBoolean(TelephonyManager.METADATA_HIDE_VOICEMAIL_SETTINGS_MENU, false)) { 375 if (DBG) { 376 log("maybeHideVoicemailSettings(): not disabled by default dialer"); 377 } 378 return; 379 } 380 getPreferenceScreen().removePreference(mVoicemailSettingsScreen); 381 if (DBG) { 382 log("maybeHideVoicemailSettings(): disabled by default dialer"); 383 } 384 } catch (NameNotFoundException e) { 385 // do nothing 386 if (DBG) { 387 log("maybeHideVoicemailSettings(): not controlled by default dialer"); 388 } 389 } 390 } 391 392 @Override onNewIntent(Intent newIntent)393 protected void onNewIntent(Intent newIntent) { 394 setIntent(newIntent); 395 396 mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, getIntent()); 397 mSubscriptionInfoHelper.setActionBarTitle( 398 getActionBar(), getResources(), R.string.call_settings_with_label); 399 mPhone = mSubscriptionInfoHelper.getPhone(); 400 } 401 log(String msg)402 private static void log(String msg) { 403 Log.d(LOG_TAG, msg); 404 } 405 406 @Override onOptionsItemSelected(MenuItem item)407 public boolean onOptionsItemSelected(MenuItem item) { 408 final int itemId = item.getItemId(); 409 if (itemId == android.R.id.home) { // See ActionBar#setDisplayHomeAsUpEnabled() 410 onBackPressed(); 411 return true; 412 } 413 return super.onOptionsItemSelected(item); 414 } 415 416 /** 417 * Finish current Activity and go up to the top level Settings ({@link CallFeaturesSetting}). 418 * This is useful for implementing "HomeAsUp" capability for second-level Settings. 419 */ goUpToTopLevelSetting( Activity activity, SubscriptionInfoHelper subscriptionInfoHelper)420 public static void goUpToTopLevelSetting( 421 Activity activity, SubscriptionInfoHelper subscriptionInfoHelper) { 422 Intent intent = subscriptionInfoHelper.getIntent(CallFeaturesSetting.class); 423 intent.setAction(Intent.ACTION_MAIN); 424 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 425 activity.startActivity(intent); 426 activity.finish(); 427 } 428 } 429