1 /* 2 * Copyright (C) 2017 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.wifi.calling; 18 19 import android.app.Activity; 20 import android.app.settings.SettingsEnums; 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.content.res.Resources; 27 import android.os.Bundle; 28 import android.os.PersistableBundle; 29 import android.telephony.CarrierConfigManager; 30 import android.telephony.ServiceState; 31 import android.telephony.SubscriptionManager; 32 import android.telephony.TelephonyCallback; 33 import android.telephony.TelephonyManager; 34 import android.telephony.ims.ImsManager; 35 import android.telephony.ims.ImsMmTelManager; 36 import android.telephony.ims.ProvisioningManager; 37 import android.text.TextUtils; 38 import android.util.Log; 39 import android.view.LayoutInflater; 40 import android.view.View; 41 import android.view.ViewGroup; 42 import android.widget.CompoundButton; 43 import android.widget.CompoundButton.OnCheckedChangeListener; 44 45 import androidx.appcompat.app.AlertDialog; 46 import androidx.preference.Preference; 47 import androidx.preference.Preference.OnPreferenceClickListener; 48 import androidx.preference.PreferenceScreen; 49 50 import com.android.ims.ImsConfig; 51 import com.android.internal.annotations.VisibleForTesting; 52 import com.android.internal.telephony.Phone; 53 import com.android.internal.telephony.flags.Flags; 54 import com.android.settings.R; 55 import com.android.settings.SettingsActivity; 56 import com.android.settings.SettingsPreferenceFragment; 57 import com.android.settings.Utils; 58 import com.android.settings.core.SubSettingLauncher; 59 import com.android.settings.network.ims.WifiCallingQueryImsState; 60 import com.android.settings.widget.SettingsMainSwitchPreference; 61 62 import java.util.List; 63 64 /** 65 * This is the inner class of {@link WifiCallingSettings} fragment. 66 * The preference screen lets you enable/disable Wi-Fi Calling and change Wi-Fi Calling mode. 67 */ 68 public class WifiCallingSettingsForSub extends SettingsPreferenceFragment 69 implements OnCheckedChangeListener, 70 Preference.OnPreferenceChangeListener { 71 private static final String TAG = "WifiCallingForSub"; 72 73 //String keys for preference lookup 74 private static final String SWITCH_BAR = "wifi_calling_switch_bar"; 75 private static final String BUTTON_WFC_MODE = "wifi_calling_mode"; 76 private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode"; 77 private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key"; 78 private static final String PREFERENCE_NO_OPTIONS_DESC = "no_options_description"; 79 80 @VisibleForTesting 81 static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1; 82 @VisibleForTesting 83 static final int REQUEST_CHECK_WFC_DISCLAIMER = 2; 84 85 public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP"; 86 public static final String EXTRA_SUB_ID = "EXTRA_SUB_ID"; 87 88 protected static final String FRAGMENT_BUNDLE_SUBID = "subId"; 89 90 public static final int LAUNCH_APP_ACTIVATE = 0; 91 public static final int LAUNCH_APP_UPDATE = 1; 92 93 //UI objects 94 private SettingsMainSwitchPreference mSwitchBar; 95 private ListWithEntrySummaryPreference mButtonWfcMode; 96 private ListWithEntrySummaryPreference mButtonWfcRoamingMode; 97 private Preference mUpdateAddress; 98 99 private boolean mEditableWfcMode = true; 100 private boolean mEditableWfcRoamingMode = true; 101 private boolean mUseWfcHomeModeForRoaming = false; 102 private boolean mOverrideWfcRoamingModeWhileUsingNtn = false; 103 104 private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 105 private ImsMmTelManager mImsMmTelManager; 106 private ProvisioningManager mProvisioningManager; 107 private TelephonyManager mTelephonyManager; 108 109 private PhoneTelephonyCallback mTelephonyCallback; 110 111 private class PhoneTelephonyCallback extends TelephonyCallback implements 112 TelephonyCallback.CallStateListener { 113 /* 114 * Enable/disable controls when in/out of a call and depending on 115 * TTY mode and TTY support over VoLTE. 116 * @see android.telephony.PhoneStateListener#onCallStateChanged(int, 117 * java.lang.String) 118 */ 119 @Override onCallStateChanged(int state)120 public void onCallStateChanged(int state) { 121 final SettingsActivity activity = (SettingsActivity) getActivity(); 122 123 boolean isWfcEnabled = false; 124 boolean isCallStateIdle = false; 125 126 final SettingsMainSwitchPreference prefSwitch = (SettingsMainSwitchPreference) 127 getPreferenceScreen().findPreference(SWITCH_BAR); 128 if (prefSwitch != null) { 129 isWfcEnabled = prefSwitch.isChecked(); 130 isCallStateIdle = getTelephonyManagerForSub( 131 WifiCallingSettingsForSub.this.mSubId).getCallStateForSubscription() 132 == TelephonyManager.CALL_STATE_IDLE; 133 134 boolean isNonTtyOrTtyOnVolteEnabled = true; 135 if (isWfcEnabled || isCallStateIdle) { 136 isNonTtyOrTtyOnVolteEnabled = 137 queryImsState(WifiCallingSettingsForSub.this.mSubId) 138 .isAllowUserControl(); 139 } 140 141 isWfcEnabled = isWfcEnabled && isNonTtyOrTtyOnVolteEnabled; 142 prefSwitch.setEnabled(isCallStateIdle && isNonTtyOrTtyOnVolteEnabled); 143 } 144 145 boolean isWfcModeEditable = true; 146 boolean isWfcRoamingModeEditable = false; 147 if (isWfcEnabled && isCallStateIdle) { 148 final CarrierConfigManager configManager = (CarrierConfigManager) 149 activity.getSystemService(Context.CARRIER_CONFIG_SERVICE); 150 if (configManager != null) { 151 PersistableBundle b = configManager.getConfigForSubId( 152 WifiCallingSettingsForSub.this.mSubId); 153 if (b != null) { 154 isWfcModeEditable = b.getBoolean( 155 CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL); 156 isWfcRoamingModeEditable = b.getBoolean( 157 CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL); 158 } 159 } 160 } else { 161 isWfcModeEditable = false; 162 isWfcRoamingModeEditable = false; 163 } 164 165 final Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE); 166 if (pref != null) { 167 pref.setEnabled(isWfcModeEditable); 168 } 169 final Preference pref_roam = 170 getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE); 171 if (pref_roam != null) { 172 pref_roam.setEnabled(isWfcRoamingModeEditable 173 && !overrideWfcRoamingModeWhileUsingNtn()); 174 } 175 } 176 } 177 178 /* 179 * Launch carrier emergency address management activity 180 */ 181 private final OnPreferenceClickListener mUpdateAddressListener = 182 preference -> { 183 final Intent carrierAppIntent = getCarrierActivityIntent(); 184 if (carrierAppIntent != null) { 185 carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUNCH_APP_UPDATE); 186 startActivity(carrierAppIntent); 187 } 188 return true; 189 }; 190 191 private final ProvisioningManager.Callback mProvisioningCallback = 192 new ProvisioningManager.Callback() { 193 @Override 194 public void onProvisioningIntChanged(int item, int value) { 195 if (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED 196 || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED) { 197 // The provisioning policy might have changed. Update the body to make sure 198 // this change takes effect if needed. 199 updateBody(); 200 } 201 } 202 }; 203 204 @VisibleForTesting showAlert(Intent intent)205 void showAlert(Intent intent) { 206 final Context context = getActivity(); 207 208 final CharSequence title = 209 intent.getCharSequenceExtra(ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_TITLE); 210 final CharSequence message = 211 intent.getCharSequenceExtra(ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE); 212 213 final AlertDialog.Builder builder = new AlertDialog.Builder(context); 214 builder.setMessage(message) 215 .setTitle(title) 216 .setIcon(android.R.drawable.ic_dialog_alert) 217 .setPositiveButton(android.R.string.ok, null); 218 final AlertDialog dialog = builder.create(); 219 dialog.show(); 220 } 221 222 private IntentFilter mIntentFilter; 223 224 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 225 @Override 226 public void onReceive(Context context, Intent intent) { 227 final String action = intent.getAction(); 228 if (action.equals(ImsManager.ACTION_WFC_IMS_REGISTRATION_ERROR)) { 229 // If this fragment is active then we are immediately 230 // showing alert on screen. There is no need to add 231 // notification in this case. 232 // 233 // In order to communicate to ImsPhone that it should 234 // not show notification, we are changing result code here. 235 setResultCode(Activity.RESULT_CANCELED); 236 237 showAlert(intent); 238 } 239 } 240 }; 241 242 @Override getMetricsCategory()243 public int getMetricsCategory() { 244 return SettingsEnums.WIFI_CALLING_FOR_SUB; 245 } 246 247 @Override getHelpResource()248 public int getHelpResource() { 249 // Return 0 to suppress help icon. The help will be populated by parent page. 250 return 0; 251 } 252 253 @VisibleForTesting getTelephonyManagerForSub(int subId)254 TelephonyManager getTelephonyManagerForSub(int subId) { 255 if (mTelephonyManager == null) { 256 mTelephonyManager = getContext().getSystemService(TelephonyManager.class); 257 } 258 return mTelephonyManager.createForSubscriptionId(subId); 259 } 260 261 @VisibleForTesting queryImsState(int subId)262 WifiCallingQueryImsState queryImsState(int subId) { 263 return new WifiCallingQueryImsState(getContext(), subId); 264 } 265 266 @VisibleForTesting getImsProvisioningManager()267 ProvisioningManager getImsProvisioningManager() { 268 if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { 269 return null; 270 } 271 return ProvisioningManager.createForSubscriptionId(mSubId); 272 } 273 274 @VisibleForTesting getImsMmTelManager()275 ImsMmTelManager getImsMmTelManager() { 276 if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { 277 return null; 278 } 279 return ImsMmTelManager.createForSubscriptionId(mSubId); 280 } 281 282 @Override onCreate(Bundle savedInstanceState)283 public void onCreate(Bundle savedInstanceState) { 284 super.onCreate(savedInstanceState); 285 286 addPreferencesFromResource(R.xml.wifi_calling_settings); 287 288 // SubId should always be specified when creating this fragment. Either through 289 // fragment.setArguments() or through savedInstanceState. 290 if (getArguments() != null && getArguments().containsKey(FRAGMENT_BUNDLE_SUBID)) { 291 mSubId = getArguments().getInt(FRAGMENT_BUNDLE_SUBID); 292 } else if (savedInstanceState != null) { 293 mSubId = savedInstanceState.getInt( 294 FRAGMENT_BUNDLE_SUBID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); 295 } 296 297 mProvisioningManager = getImsProvisioningManager(); 298 mImsMmTelManager = getImsMmTelManager(); 299 300 mSwitchBar = (SettingsMainSwitchPreference) findPreference(SWITCH_BAR); 301 302 mButtonWfcMode = findPreference(BUTTON_WFC_MODE); 303 mButtonWfcMode.setOnPreferenceChangeListener(this); 304 305 mButtonWfcRoamingMode = findPreference(BUTTON_WFC_ROAMING_MODE); 306 mButtonWfcRoamingMode.setOnPreferenceChangeListener(this); 307 308 mUpdateAddress = findPreference(PREFERENCE_EMERGENCY_ADDRESS); 309 mUpdateAddress.setOnPreferenceClickListener(mUpdateAddressListener); 310 311 mIntentFilter = new IntentFilter(); 312 mIntentFilter.addAction(ImsManager.ACTION_WFC_IMS_REGISTRATION_ERROR); 313 314 updateDescriptionForOptions( 315 List.of(mButtonWfcMode, mButtonWfcRoamingMode, mUpdateAddress)); 316 } 317 318 @Override onSaveInstanceState(Bundle outState)319 public void onSaveInstanceState(Bundle outState) { 320 outState.putInt(FRAGMENT_BUNDLE_SUBID, mSubId); 321 super.onSaveInstanceState(outState); 322 } 323 324 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)325 public View onCreateView(LayoutInflater inflater, ViewGroup container, 326 Bundle savedInstanceState) { 327 328 final View view = inflater.inflate( 329 R.layout.wifi_calling_settings_preferences, container, false); 330 331 final ViewGroup prefs_container = view.findViewById(android.R.id.tabcontent); 332 Utils.prepareCustomPreferencesList(container, view, prefs_container, false); 333 final View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState); 334 prefs_container.addView(prefs); 335 336 return view; 337 } 338 339 @VisibleForTesting isWfcProvisionedOnDevice()340 boolean isWfcProvisionedOnDevice() { 341 return queryImsState(mSubId).isWifiCallingProvisioned(); 342 } 343 updateBody()344 private void updateBody() { 345 if (!isWfcProvisionedOnDevice()) { 346 // This screen is not allowed to be shown due to provisioning policy and should 347 // therefore be closed. 348 finish(); 349 return; 350 } 351 352 final CarrierConfigManager configManager = (CarrierConfigManager) 353 getSystemService(Context.CARRIER_CONFIG_SERVICE); 354 boolean isWifiOnlySupported = true; 355 356 if (configManager != null) { 357 final PersistableBundle b = configManager.getConfigForSubId(mSubId); 358 if (b != null) { 359 mEditableWfcMode = b.getBoolean( 360 CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL); 361 mEditableWfcRoamingMode = b.getBoolean( 362 CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL); 363 mUseWfcHomeModeForRoaming = b.getBoolean( 364 CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, 365 false); 366 isWifiOnlySupported = b.getBoolean( 367 CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true); 368 mOverrideWfcRoamingModeWhileUsingNtn = b.getBoolean( 369 CarrierConfigManager.KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL, 370 true); 371 } 372 } 373 374 final Resources res = getResourcesForSubId(); 375 mButtonWfcMode.setTitle(res.getString(R.string.wifi_calling_mode_title)); 376 mButtonWfcMode.setDialogTitle(res.getString(R.string.wifi_calling_mode_dialog_title)); 377 mButtonWfcRoamingMode.setTitle(res.getString(R.string.wifi_calling_roaming_mode_title)); 378 mButtonWfcRoamingMode.setDialogTitle( 379 res.getString(R.string.wifi_calling_roaming_mode_dialog_title)); 380 381 if (isWifiOnlySupported) { 382 // Set string resources WITH option wifi only in mButtonWfcMode. 383 mButtonWfcMode.setEntries( 384 res.getStringArray(R.array.wifi_calling_mode_choices)); 385 mButtonWfcMode.setEntryValues(res.getStringArray(R.array.wifi_calling_mode_values)); 386 mButtonWfcMode.setEntrySummaries( 387 res.getStringArray(R.array.wifi_calling_mode_summaries)); 388 389 // Set string resources WITH option wifi only in mButtonWfcRoamingMode. 390 mButtonWfcRoamingMode.setEntries( 391 res.getStringArray(R.array.wifi_calling_mode_choices_v2)); 392 mButtonWfcRoamingMode.setEntryValues( 393 res.getStringArray(R.array.wifi_calling_mode_values)); 394 mButtonWfcRoamingMode.setEntrySummaries( 395 res.getStringArray(R.array.wifi_calling_mode_summaries)); 396 } else { 397 // Set string resources WITHOUT option wifi only in mButtonWfcMode. 398 mButtonWfcMode.setEntries( 399 res.getStringArray(R.array.wifi_calling_mode_choices_without_wifi_only)); 400 mButtonWfcMode.setEntryValues( 401 res.getStringArray(R.array.wifi_calling_mode_values_without_wifi_only)); 402 mButtonWfcMode.setEntrySummaries( 403 res.getStringArray(R.array.wifi_calling_mode_summaries_without_wifi_only)); 404 405 // Set string resources WITHOUT option wifi only in mButtonWfcRoamingMode. 406 mButtonWfcRoamingMode.setEntries( 407 res.getStringArray(R.array.wifi_calling_mode_choices_v2_without_wifi_only)); 408 mButtonWfcRoamingMode.setEntryValues( 409 res.getStringArray(R.array.wifi_calling_mode_values_without_wifi_only)); 410 mButtonWfcRoamingMode.setEntrySummaries( 411 res.getStringArray(R.array.wifi_calling_mode_summaries_without_wifi_only)); 412 } 413 414 // NOTE: Buttons will be enabled/disabled in mTelephonyCallback 415 final WifiCallingQueryImsState queryIms = queryImsState(mSubId); 416 final boolean wfcEnabled = queryIms.isEnabledByUser() 417 && queryIms.isAllowUserControl(); 418 mSwitchBar.setChecked(wfcEnabled); 419 int wfcMode = ImsMmTelManager.WIFI_MODE_UNKNOWN; 420 int wfcRoamingMode = ImsMmTelManager.WIFI_MODE_UNKNOWN; 421 boolean hasException = false; 422 try { 423 wfcMode = mImsMmTelManager.getVoWiFiModeSetting(); 424 wfcRoamingMode = mImsMmTelManager.getVoWiFiRoamingModeSetting(); 425 } catch (IllegalArgumentException e) { 426 hasException = true; 427 Log.e(TAG, "getResourceIdForWfcMode: Exception", e); 428 } 429 mButtonWfcMode.setValue(Integer.toString(wfcMode)); 430 mButtonWfcRoamingMode.setValue(Integer.toString(wfcRoamingMode)); 431 updateButtonWfcMode(wfcEnabled && !hasException, wfcMode, wfcRoamingMode); 432 } 433 434 @Override onResume()435 public void onResume() { 436 super.onResume(); 437 updateBody(); 438 Context context = getActivity(); 439 if (mTelephonyCallback == null && queryImsState(mSubId).isWifiCallingSupported()) { 440 mTelephonyCallback = new PhoneTelephonyCallback(); 441 getTelephonyManagerForSub(mSubId).registerTelephonyCallback( 442 context.getMainExecutor(), mTelephonyCallback); 443 mSwitchBar.addOnSwitchChangeListener(this); 444 } 445 context.registerReceiver(mIntentReceiver, mIntentFilter, 446 Context.RECEIVER_EXPORTED_UNAUDITED); 447 final Intent intent = getActivity().getIntent(); 448 if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) { 449 showAlert(intent); 450 } 451 // Register callback for provisioning changes. 452 registerProvisioningChangedCallback(); 453 } 454 455 @Override onPause()456 public void onPause() { 457 super.onPause(); 458 Context context = getActivity(); 459 if (mTelephonyCallback != null) { 460 getTelephonyManagerForSub(mSubId).unregisterTelephonyCallback(mTelephonyCallback); 461 mTelephonyCallback = null; 462 mSwitchBar.removeOnSwitchChangeListener(this); 463 } 464 context.unregisterReceiver(mIntentReceiver); 465 // Remove callback for provisioning changes. 466 unregisterProvisioningChangedCallback(); 467 } 468 469 /** 470 * Listens to the state change of the switch. 471 */ 472 @Override onCheckedChanged(CompoundButton buttonView, boolean isChecked)473 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 474 Log.d(TAG, "onSwitchChanged(" + isChecked + ")"); 475 476 if (!isChecked) { 477 updateWfcMode(false); 478 return; 479 } 480 481 // Launch disclaimer fragment before turning on WFC 482 final Context context = getActivity(); 483 final Bundle args = new Bundle(); 484 args.putInt(EXTRA_SUB_ID, mSubId); 485 new SubSettingLauncher(context) 486 .setDestination(WifiCallingDisclaimerFragment.class.getName()) 487 .setArguments(args) 488 .setTitleRes(R.string.wifi_calling_settings_title) 489 .setSourceMetricsCategory(getMetricsCategory()) 490 .setResultListener(this, REQUEST_CHECK_WFC_DISCLAIMER) 491 .launch(); 492 } 493 494 /* 495 * Get the Intent to launch carrier emergency address management activity. 496 * Return null when no activity found. 497 */ getCarrierActivityIntent()498 private Intent getCarrierActivityIntent() { 499 // Retrieve component name from carrier config 500 final CarrierConfigManager configManager = 501 getActivity().getSystemService(CarrierConfigManager.class); 502 if (configManager == null) return null; 503 504 final PersistableBundle bundle = configManager.getConfigForSubId(mSubId); 505 if (bundle == null) return null; 506 507 final String carrierApp = bundle.getString( 508 CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING); 509 if (TextUtils.isEmpty(carrierApp)) return null; 510 511 final ComponentName componentName = ComponentName.unflattenFromString(carrierApp); 512 if (componentName == null) return null; 513 514 // Build and return intent 515 final Intent intent = new Intent(); 516 intent.setComponent(componentName); 517 intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mSubId); 518 return intent; 519 } 520 521 /* 522 * Turn on/off WFC mode with ImsManager and update UI accordingly 523 */ updateWfcMode(boolean wfcEnabled)524 private void updateWfcMode(boolean wfcEnabled) { 525 Log.i(TAG, "updateWfcMode(" + wfcEnabled + ")"); 526 boolean hasException = false; 527 try { 528 mImsMmTelManager.setVoWiFiSettingEnabled(wfcEnabled); 529 } catch (IllegalArgumentException e) { 530 Log.e(TAG, "updateWfcMode: Exception", e); 531 hasException = true; 532 } 533 534 int wfcMode = ImsMmTelManager.WIFI_MODE_UNKNOWN; 535 int wfcRoamingMode = ImsMmTelManager.WIFI_MODE_UNKNOWN; 536 if (!hasException) { 537 try { 538 wfcMode = mImsMmTelManager.getVoWiFiModeSetting(); 539 wfcRoamingMode = mImsMmTelManager.getVoWiFiRoamingModeSetting(); 540 } catch (IllegalArgumentException e) { 541 hasException = true; 542 Log.e(TAG, "updateWfcMode: Exception", e); 543 } 544 } 545 updateButtonWfcMode(wfcEnabled && !hasException, wfcMode, wfcRoamingMode); 546 if (wfcEnabled) { 547 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), wfcMode); 548 } else { 549 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), -1); 550 } 551 } 552 553 @Override onActivityResult(int requestCode, int resultCode, Intent data)554 public void onActivityResult(int requestCode, int resultCode, Intent data) { 555 super.onActivityResult(requestCode, resultCode, data); 556 Log.d(TAG, "WFC activity request = " + requestCode + " result = " + resultCode); 557 switch (requestCode) { 558 case REQUEST_CHECK_WFC_EMERGENCY_ADDRESS: 559 if (resultCode == Activity.RESULT_OK) { 560 updateWfcMode(true); 561 } 562 break; 563 case REQUEST_CHECK_WFC_DISCLAIMER: 564 if (resultCode == Activity.RESULT_OK) { 565 // Call address management activity before turning on WFC 566 final Intent carrierAppIntent = getCarrierActivityIntent(); 567 if (carrierAppIntent != null) { 568 carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUNCH_APP_ACTIVATE); 569 startActivityForResult(carrierAppIntent, 570 REQUEST_CHECK_WFC_EMERGENCY_ADDRESS); 571 } else { 572 updateWfcMode(true); 573 } 574 } 575 break; 576 default: 577 Log.e(TAG, "Unexpected request: " + requestCode); 578 break; 579 } 580 } 581 updateButtonWfcMode(boolean wfcEnabled, int wfcMode, int wfcRoamingMode)582 private void updateButtonWfcMode(boolean wfcEnabled, 583 int wfcMode, int wfcRoamingMode) { 584 mButtonWfcMode.setSummary(getWfcModeSummary(wfcMode)); 585 mButtonWfcMode.setEnabled(wfcEnabled && mEditableWfcMode); 586 // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value. 587 mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode 588 && !overrideWfcRoamingModeWhileUsingNtn()); 589 590 final PreferenceScreen preferenceScreen = getPreferenceScreen(); 591 final boolean updateAddressEnabled = (getCarrierActivityIntent() != null); 592 if (wfcEnabled) { 593 // Don't show WFC (home) preference if it's not editable. 594 mButtonWfcMode.setVisible(mEditableWfcMode); 595 // Don't show WFC roaming preference if it's not editable. 596 mButtonWfcRoamingMode.setVisible( 597 mEditableWfcRoamingMode && !mUseWfcHomeModeForRoaming); 598 mUpdateAddress.setVisible(updateAddressEnabled); 599 } else { 600 mButtonWfcMode.setVisible(false); 601 mButtonWfcRoamingMode.setVisible(false); 602 mUpdateAddress.setVisible(false); 603 } 604 updateDescriptionForOptions( 605 List.of(mButtonWfcMode, mButtonWfcRoamingMode, mUpdateAddress)); 606 } 607 updateDescriptionForOptions(List<Preference> visibleOptions)608 private void updateDescriptionForOptions(List<Preference> visibleOptions) { 609 LinkifyDescriptionPreference pref = findPreference(PREFERENCE_NO_OPTIONS_DESC); 610 if (pref == null) { 611 return; 612 } 613 614 boolean optionsAvailable = visibleOptions.stream().anyMatch(Preference::isVisible); 615 if (!optionsAvailable) { 616 final Resources res = getResourcesForSubId(); 617 String emptyViewText = res.getString(R.string.wifi_calling_off_explanation, 618 res.getString(R.string.wifi_calling_off_explanation_2)); 619 pref.setSummary(emptyViewText); 620 } 621 pref.setVisible(!optionsAvailable); 622 } 623 624 @Override onPreferenceChange(Preference preference, Object newValue)625 public boolean onPreferenceChange(Preference preference, Object newValue) { 626 boolean hasException = false; 627 628 if (preference == mButtonWfcMode) { 629 Log.d(TAG, "onPreferenceChange mButtonWfcMode " + newValue); 630 mButtonWfcMode.setValue((String) newValue); 631 final int buttonMode = Integer.valueOf((String) newValue); 632 int currentWfcMode = ImsMmTelManager.WIFI_MODE_UNKNOWN; 633 try { 634 currentWfcMode = mImsMmTelManager.getVoWiFiModeSetting(); 635 } catch (IllegalArgumentException e) { 636 hasException = true; 637 Log.e(TAG, "onPreferenceChange: Exception", e); 638 } 639 if (buttonMode != currentWfcMode && !hasException) { 640 try { 641 mImsMmTelManager.setVoWiFiModeSetting(buttonMode); 642 mButtonWfcMode.setSummary(getWfcModeSummary(buttonMode)); 643 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode); 644 645 if (mUseWfcHomeModeForRoaming) { 646 mImsMmTelManager.setVoWiFiRoamingModeSetting(buttonMode); 647 // mButtonWfcRoamingMode.setSummary is not needed; summary is selected value 648 } 649 } catch (IllegalArgumentException e) { 650 Log.e(TAG, "onPreferenceChange: Exception", e); 651 } 652 } 653 } else if (preference == mButtonWfcRoamingMode) { 654 mButtonWfcRoamingMode.setValue((String) newValue); 655 final int buttonMode = Integer.valueOf((String) newValue); 656 int currentMode = ImsMmTelManager.WIFI_MODE_UNKNOWN; 657 try { 658 currentMode = mImsMmTelManager.getVoWiFiRoamingModeSetting(); 659 } catch (IllegalArgumentException e) { 660 hasException = true; 661 Log.e(TAG, "updateWfcMode: Exception", e); 662 } 663 if (buttonMode != currentMode && !hasException) { 664 try { 665 mImsMmTelManager.setVoWiFiRoamingModeSetting(buttonMode); 666 // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected 667 // value. 668 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode); 669 } catch (IllegalArgumentException e) { 670 Log.e(TAG, "onPreferenceChange: Exception", e); 671 } 672 } 673 } 674 return true; 675 } 676 getWfcModeSummary(int wfcMode)677 private CharSequence getWfcModeSummary(int wfcMode) { 678 int resId = com.android.internal.R.string.wifi_calling_off_summary; 679 if (queryImsState(mSubId).isEnabledByUser()) { 680 switch (wfcMode) { 681 case ImsMmTelManager.WIFI_MODE_WIFI_ONLY: 682 resId = com.android.internal.R.string.wfc_mode_wifi_only_summary; 683 break; 684 case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED: 685 resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary; 686 break; 687 case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED: 688 resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary; 689 break; 690 default: 691 Log.e(TAG, "Unexpected WFC mode value: " + wfcMode); 692 } 693 } 694 return getResourcesForSubId().getString(resId); 695 } 696 697 @VisibleForTesting getResourcesForSubId()698 Resources getResourcesForSubId() { 699 return SubscriptionManager.getResourcesForSubId(getContext(), mSubId); 700 } 701 702 @VisibleForTesting registerProvisioningChangedCallback()703 void registerProvisioningChangedCallback() { 704 if (mProvisioningManager == null) { 705 return; 706 } 707 try { 708 mProvisioningManager.registerProvisioningChangedCallback(getContext().getMainExecutor(), 709 mProvisioningCallback); 710 } catch (Exception ex) { 711 Log.w(TAG, "onResume: Unable to register callback for provisioning changes."); 712 } 713 } 714 715 @VisibleForTesting unregisterProvisioningChangedCallback()716 void unregisterProvisioningChangedCallback() { 717 if (mProvisioningManager == null) { 718 return; 719 } 720 mProvisioningManager.unregisterProvisioningChangedCallback(mProvisioningCallback); 721 } 722 723 /** 724 * Determine whether to override roaming Wi-Fi calling preference when device is connected to 725 * non-terrestrial network. 726 * 727 * @return {@code true} if phone is connected to non-terrestrial network and if 728 * {@link CarrierConfigManager#KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL} is true, 729 * {@code false} otherwise. 730 */ overrideWfcRoamingModeWhileUsingNtn()731 private boolean overrideWfcRoamingModeWhileUsingNtn() { 732 if (!Flags.carrierEnabledSatelliteFlag()) { 733 return false; 734 } 735 736 TelephonyManager tm = getTelephonyManagerForSub(mSubId); 737 ServiceState serviceState = tm.getServiceState(); 738 if (serviceState == null) { 739 return false; 740 } 741 742 if (!serviceState.isUsingNonTerrestrialNetwork()) { 743 return false; 744 } 745 746 return mOverrideWfcRoamingModeWhileUsingNtn; 747 } 748 } 749