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