1 /* 2 * Copyright (C) 2015 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.settings; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.content.BroadcastReceiver; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.os.Bundle; 27 import android.os.PersistableBundle; 28 import android.support.v7.preference.ListPreference; 29 import android.support.v7.preference.Preference; 30 import android.support.v7.preference.Preference.OnPreferenceClickListener; 31 import android.support.v7.preference.PreferenceScreen; 32 import android.telephony.CarrierConfigManager; 33 import android.telephony.PhoneStateListener; 34 import android.telephony.TelephonyManager; 35 import android.text.TextUtils; 36 import android.util.Log; 37 import android.widget.Switch; 38 import android.widget.TextView; 39 40 import com.android.ims.ImsConfig; 41 import com.android.ims.ImsManager; 42 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 43 import com.android.internal.telephony.Phone; 44 import com.android.settings.widget.SwitchBar; 45 46 /** 47 * "Wi-Fi Calling settings" screen. This preference screen lets you 48 * enable/disable Wi-Fi Calling and change Wi-Fi Calling mode. 49 */ 50 public class WifiCallingSettings extends SettingsPreferenceFragment 51 implements SwitchBar.OnSwitchChangeListener, 52 Preference.OnPreferenceChangeListener { 53 54 private static final String TAG = "WifiCallingSettings"; 55 56 //String keys for preference lookup 57 private static final String BUTTON_WFC_MODE = "wifi_calling_mode"; 58 private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode"; 59 private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key"; 60 61 private static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1; 62 63 public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP"; 64 65 public static final int LAUCH_APP_ACTIVATE = 0; 66 public static final int LAUCH_APP_UPDATE = 1; 67 68 //UI objects 69 private SwitchBar mSwitchBar; 70 private Switch mSwitch; 71 private ListPreference mButtonWfcMode; 72 private ListPreference mButtonWfcRoamingMode; 73 private Preference mUpdateAddress; 74 private TextView mEmptyView; 75 76 private boolean mValidListener = false; 77 private boolean mEditableWfcMode = true; 78 private boolean mEditableWfcRoamingMode = true; 79 80 private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 81 /* 82 * Enable/disable controls when in/out of a call and depending on 83 * TTY mode and TTY support over VoLTE. 84 * @see android.telephony.PhoneStateListener#onCallStateChanged(int, 85 * java.lang.String) 86 */ 87 @Override 88 public void onCallStateChanged(int state, String incomingNumber) { 89 final SettingsActivity activity = (SettingsActivity) getActivity(); 90 boolean isNonTtyOrTtyOnVolteEnabled = ImsManager 91 .isNonTtyOrTtyOnVolteEnabled(activity); 92 final SwitchBar switchBar = activity.getSwitchBar(); 93 boolean isWfcEnabled = switchBar.getSwitch().isChecked() 94 && isNonTtyOrTtyOnVolteEnabled; 95 96 switchBar.setEnabled((state == TelephonyManager.CALL_STATE_IDLE) 97 && isNonTtyOrTtyOnVolteEnabled); 98 99 boolean isWfcModeEditable = true; 100 boolean isWfcRoamingModeEditable = false; 101 final CarrierConfigManager configManager = (CarrierConfigManager) 102 activity.getSystemService(Context.CARRIER_CONFIG_SERVICE); 103 if (configManager != null) { 104 PersistableBundle b = configManager.getConfig(); 105 if (b != null) { 106 isWfcModeEditable = b.getBoolean( 107 CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL); 108 isWfcRoamingModeEditable = b.getBoolean( 109 CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL); 110 } 111 } 112 113 Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE); 114 if (pref != null) { 115 pref.setEnabled(isWfcEnabled && isWfcModeEditable 116 && (state == TelephonyManager.CALL_STATE_IDLE)); 117 } 118 Preference pref_roam = getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE); 119 if (pref_roam != null) { 120 pref_roam.setEnabled(isWfcEnabled && isWfcRoamingModeEditable 121 && (state == TelephonyManager.CALL_STATE_IDLE)); 122 } 123 } 124 }; 125 126 private final OnPreferenceClickListener mUpdateAddressListener = 127 new OnPreferenceClickListener() { 128 /* 129 * Launch carrier emergency address managemnent activity 130 */ 131 @Override 132 public boolean onPreferenceClick(Preference preference) { 133 final Context context = getActivity(); 134 Intent carrierAppIntent = getCarrierActivityIntent(context); 135 if (carrierAppIntent != null) { 136 carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_UPDATE); 137 startActivity(carrierAppIntent); 138 } 139 return true; 140 } 141 }; 142 143 @Override onActivityCreated(Bundle savedInstanceState)144 public void onActivityCreated(Bundle savedInstanceState) { 145 super.onActivityCreated(savedInstanceState); 146 147 final SettingsActivity activity = (SettingsActivity) getActivity(); 148 149 mSwitchBar = activity.getSwitchBar(); 150 mSwitch = mSwitchBar.getSwitch(); 151 mSwitchBar.show(); 152 153 mEmptyView = (TextView) getView().findViewById(android.R.id.empty); 154 setEmptyView(mEmptyView); 155 mEmptyView.setText(R.string.wifi_calling_off_explanation); 156 } 157 158 @Override onDestroyView()159 public void onDestroyView() { 160 super.onDestroyView(); 161 mSwitchBar.hide(); 162 } 163 showAlert(Intent intent)164 private void showAlert(Intent intent) { 165 Context context = getActivity(); 166 167 CharSequence title = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_TITLE); 168 CharSequence message = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_MESSAGE); 169 170 AlertDialog.Builder builder = new AlertDialog.Builder(context); 171 builder.setMessage(message) 172 .setTitle(title) 173 .setIcon(android.R.drawable.ic_dialog_alert) 174 .setPositiveButton(android.R.string.ok, null); 175 AlertDialog dialog = builder.create(); 176 dialog.show(); 177 } 178 179 private IntentFilter mIntentFilter; 180 181 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 182 @Override 183 public void onReceive(Context context, Intent intent) { 184 String action = intent.getAction(); 185 if (action.equals(ImsManager.ACTION_IMS_REGISTRATION_ERROR)) { 186 // If this fragment is active then we are immediately 187 // showing alert on screen. There is no need to add 188 // notification in this case. 189 // 190 // In order to communicate to ImsPhone that it should 191 // not show notification, we are changing result code here. 192 setResultCode(Activity.RESULT_CANCELED); 193 194 // UX requirement is to disable WFC in case of "permanent" registration failures. 195 mSwitch.setChecked(false); 196 197 showAlert(intent); 198 } 199 } 200 }; 201 202 @Override getMetricsCategory()203 public int getMetricsCategory() { 204 return MetricsEvent.WIFI_CALLING; 205 } 206 207 @Override onCreate(Bundle savedInstanceState)208 public void onCreate(Bundle savedInstanceState) { 209 super.onCreate(savedInstanceState); 210 211 addPreferencesFromResource(R.xml.wifi_calling_settings); 212 213 mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE); 214 mButtonWfcMode.setOnPreferenceChangeListener(this); 215 216 mButtonWfcRoamingMode = (ListPreference) findPreference(BUTTON_WFC_ROAMING_MODE); 217 mButtonWfcRoamingMode.setOnPreferenceChangeListener(this); 218 219 mUpdateAddress = (Preference) findPreference(PREFERENCE_EMERGENCY_ADDRESS); 220 mUpdateAddress.setOnPreferenceClickListener(mUpdateAddressListener); 221 222 mIntentFilter = new IntentFilter(); 223 mIntentFilter.addAction(ImsManager.ACTION_IMS_REGISTRATION_ERROR); 224 225 CarrierConfigManager configManager = (CarrierConfigManager) 226 getSystemService(Context.CARRIER_CONFIG_SERVICE); 227 boolean isWifiOnlySupported = true; 228 if (configManager != null) { 229 PersistableBundle b = configManager.getConfig(); 230 if (b != null) { 231 mEditableWfcMode = b.getBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL); 232 mEditableWfcRoamingMode = b.getBoolean( 233 CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL); 234 isWifiOnlySupported = b.getBoolean( 235 CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true); 236 } 237 } 238 239 if (!isWifiOnlySupported) { 240 mButtonWfcMode.setEntries(R.array.wifi_calling_mode_choices_without_wifi_only); 241 mButtonWfcMode.setEntryValues(R.array.wifi_calling_mode_values_without_wifi_only); 242 mButtonWfcRoamingMode.setEntries( 243 R.array.wifi_calling_mode_choices_v2_without_wifi_only); 244 mButtonWfcRoamingMode.setEntryValues( 245 R.array.wifi_calling_mode_values_without_wifi_only); 246 } 247 } 248 249 @Override onResume()250 public void onResume() { 251 super.onResume(); 252 253 final Context context = getActivity(); 254 255 // NOTE: Buttons will be enabled/disabled in mPhoneStateListener 256 boolean wfcEnabled = ImsManager.isWfcEnabledByUser(context) 257 && ImsManager.isNonTtyOrTtyOnVolteEnabled(context); 258 mSwitch.setChecked(wfcEnabled); 259 int wfcMode = ImsManager.getWfcMode(context, false); 260 int wfcRoamingMode = ImsManager.getWfcMode(context, true); 261 mButtonWfcMode.setValue(Integer.toString(wfcMode)); 262 mButtonWfcRoamingMode.setValue(Integer.toString(wfcRoamingMode)); 263 updateButtonWfcMode(context, wfcEnabled, wfcMode, wfcRoamingMode); 264 265 if (ImsManager.isWfcEnabledByPlatform(context)) { 266 TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 267 tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 268 269 mSwitchBar.addOnSwitchChangeListener(this); 270 271 mValidListener = true; 272 } 273 274 context.registerReceiver(mIntentReceiver, mIntentFilter); 275 276 Intent intent = getActivity().getIntent(); 277 if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) { 278 showAlert(intent); 279 } 280 } 281 282 @Override onPause()283 public void onPause() { 284 super.onPause(); 285 286 final Context context = getActivity(); 287 288 if (mValidListener) { 289 mValidListener = false; 290 291 TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 292 tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); 293 294 mSwitchBar.removeOnSwitchChangeListener(this); 295 } 296 297 context.unregisterReceiver(mIntentReceiver); 298 } 299 300 /** 301 * Listens to the state change of the switch. 302 */ 303 @Override onSwitchChanged(Switch switchView, boolean isChecked)304 public void onSwitchChanged(Switch switchView, boolean isChecked) { 305 final Context context = getActivity(); 306 Log.d(TAG, "onSwitchChanged(" + isChecked + ")"); 307 308 if (!isChecked) { 309 updateWfcMode(context, false); 310 return; 311 } 312 313 // Call address management activity before turning on WFC 314 Intent carrierAppIntent = getCarrierActivityIntent(context); 315 if (carrierAppIntent != null) { 316 carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE); 317 startActivityForResult(carrierAppIntent, REQUEST_CHECK_WFC_EMERGENCY_ADDRESS); 318 } else { 319 updateWfcMode(context, true); 320 } 321 } 322 323 /* 324 * Get the Intent to launch carrier emergency address management activity. 325 * Return null when no activity found. 326 */ getCarrierActivityIntent(Context context)327 private static Intent getCarrierActivityIntent(Context context) { 328 // Retrive component name from carrirt config 329 CarrierConfigManager configManager = context.getSystemService(CarrierConfigManager.class); 330 if (configManager == null) return null; 331 332 PersistableBundle bundle = configManager.getConfig(); 333 if (bundle == null) return null; 334 335 String carrierApp = bundle.getString( 336 CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING); 337 if (TextUtils.isEmpty(carrierApp)) return null; 338 339 ComponentName componentName = ComponentName.unflattenFromString(carrierApp); 340 if (componentName == null) return null; 341 342 // Build and return intent 343 Intent intent = new Intent(); 344 intent.setComponent(componentName); 345 return intent; 346 } 347 348 /* 349 * Turn on/off WFC mode with ImsManager and update UI accordingly 350 */ updateWfcMode(Context context, boolean wfcEnabled)351 private void updateWfcMode(Context context, boolean wfcEnabled) { 352 Log.i(TAG, "updateWfcMode(" + wfcEnabled + ")"); 353 ImsManager.setWfcSetting(context, wfcEnabled); 354 355 int wfcMode = ImsManager.getWfcMode(context, false); 356 int wfcRoamingMode = ImsManager.getWfcMode(context, true); 357 updateButtonWfcMode(context, wfcEnabled, wfcMode, wfcRoamingMode); 358 if (wfcEnabled) { 359 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), wfcMode); 360 } else { 361 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), -1); 362 } 363 } 364 365 @Override onActivityResult(int requestCode, int resultCode, Intent data)366 public void onActivityResult(int requestCode, int resultCode, Intent data) { 367 super.onActivityResult(requestCode, resultCode, data); 368 369 final Context context = getActivity(); 370 371 if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) { 372 Log.d(TAG, "WFC emergency address activity result = " + resultCode); 373 374 if (resultCode == Activity.RESULT_OK) { 375 updateWfcMode(context, true); 376 } 377 } 378 } 379 updateButtonWfcMode(Context context, boolean wfcEnabled, int wfcMode, int wfcRoamingMode)380 private void updateButtonWfcMode(Context context, boolean wfcEnabled, 381 int wfcMode, int wfcRoamingMode) { 382 mButtonWfcMode.setSummary(getWfcModeSummary(context, wfcMode)); 383 mButtonWfcMode.setEnabled(wfcEnabled && mEditableWfcMode); 384 // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value. 385 mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode); 386 387 final PreferenceScreen preferenceScreen = getPreferenceScreen(); 388 boolean updateAddressEnabled = (getCarrierActivityIntent(context) != null); 389 if (wfcEnabled) { 390 if (mEditableWfcMode) { 391 preferenceScreen.addPreference(mButtonWfcMode); 392 } else { 393 // Don't show WFC (home) preference if it's not editable. 394 preferenceScreen.removePreference(mButtonWfcMode); 395 } 396 if (mEditableWfcRoamingMode) { 397 preferenceScreen.addPreference(mButtonWfcRoamingMode); 398 } else { 399 // Don't show WFC roaming preference if it's not editable. 400 preferenceScreen.removePreference(mButtonWfcRoamingMode); 401 } 402 if (updateAddressEnabled) { 403 preferenceScreen.addPreference(mUpdateAddress); 404 } else { 405 preferenceScreen.removePreference(mUpdateAddress); 406 } 407 } else { 408 preferenceScreen.removePreference(mButtonWfcMode); 409 preferenceScreen.removePreference(mButtonWfcRoamingMode); 410 preferenceScreen.removePreference(mUpdateAddress); 411 } 412 } 413 414 @Override onPreferenceChange(Preference preference, Object newValue)415 public boolean onPreferenceChange(Preference preference, Object newValue) { 416 final Context context = getActivity(); 417 if (preference == mButtonWfcMode) { 418 mButtonWfcMode.setValue((String) newValue); 419 int buttonMode = Integer.valueOf((String) newValue); 420 int currentWfcMode = ImsManager.getWfcMode(context, false); 421 if (buttonMode != currentWfcMode) { 422 ImsManager.setWfcMode(context, buttonMode, false); 423 mButtonWfcMode.setSummary(getWfcModeSummary(context, buttonMode)); 424 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode); 425 } 426 if (!mEditableWfcRoamingMode) { 427 int currentWfcRoamingMode = ImsManager.getWfcMode(context, true); 428 if (buttonMode != currentWfcRoamingMode) { 429 ImsManager.setWfcMode(context, buttonMode, true); 430 // mButtonWfcRoamingMode.setSummary is not needed; summary is selected value 431 } 432 } 433 } else if (preference == mButtonWfcRoamingMode) { 434 mButtonWfcRoamingMode.setValue((String) newValue); 435 int buttonMode = Integer.valueOf((String) newValue); 436 int currentMode = ImsManager.getWfcMode(context, true); 437 if (buttonMode != currentMode) { 438 ImsManager.setWfcMode(context, buttonMode, true); 439 // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value. 440 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode); 441 } 442 } 443 return true; 444 } 445 getWfcModeSummary(Context context, int wfcMode)446 public static int getWfcModeSummary(Context context, int wfcMode) { 447 int resId = com.android.internal.R.string.wifi_calling_off_summary; 448 if (ImsManager.isWfcEnabledByUser(context)) { 449 switch (wfcMode) { 450 case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY: 451 resId = com.android.internal.R.string.wfc_mode_wifi_only_summary; 452 break; 453 case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED: 454 resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary; 455 break; 456 case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED: 457 resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary; 458 break; 459 default: 460 Log.e(TAG, "Unexpected WFC mode value: " + wfcMode); 461 } 462 } 463 return resId; 464 } 465 } 466