1 /* 2 * Copyright (C) 2018 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.network.telephony; 18 19 import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI; 20 21 import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.CDMA; 22 import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.EVDO; 23 import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.GSM; 24 import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.LTE; 25 import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.NR; 26 import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.RAF_TD_SCDMA; 27 import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.RAF_UNKNOWN; 28 import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.WCDMA; 29 import static com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO; 30 import static com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA; 31 import static com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO; 32 import static com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA; 33 34 import android.annotation.Nullable; 35 import android.content.ContentResolver; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.content.pm.PackageManager; 39 import android.content.pm.ResolveInfo; 40 import android.database.Cursor; 41 import android.graphics.Color; 42 import android.graphics.drawable.ColorDrawable; 43 import android.graphics.drawable.Drawable; 44 import android.graphics.drawable.LayerDrawable; 45 import android.net.ConnectivityManager; 46 import android.net.Network; 47 import android.net.NetworkCapabilities; 48 import android.os.PersistableBundle; 49 import android.os.SystemClock; 50 import android.os.SystemProperties; 51 import android.provider.Settings; 52 import android.telecom.PhoneAccountHandle; 53 import android.telecom.TelecomManager; 54 import android.telephony.CarrierConfigManager; 55 import android.telephony.ServiceState; 56 import android.telephony.SubscriptionInfo; 57 import android.telephony.SubscriptionManager; 58 import android.telephony.TelephonyManager; 59 import android.telephony.euicc.EuiccManager; 60 import android.telephony.ims.ImsManager; 61 import android.telephony.ims.ImsRcsManager; 62 import android.telephony.ims.ProvisioningManager; 63 import android.telephony.ims.RcsUceAdapter; 64 import android.telephony.ims.feature.MmTelFeature; 65 import android.telephony.ims.stub.ImsRegistrationImplBase; 66 import android.text.TextUtils; 67 import android.util.Log; 68 import android.view.Gravity; 69 70 import androidx.annotation.VisibleForTesting; 71 72 import com.android.internal.util.ArrayUtils; 73 import com.android.settings.R; 74 import com.android.settings.Utils; 75 import com.android.settings.core.BasePreferenceController; 76 import com.android.settings.network.SubscriptionUtil; 77 import com.android.settings.network.ims.WifiCallingQueryImsState; 78 import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants; 79 import com.android.settingslib.development.DevelopmentSettingsEnabler; 80 import com.android.settingslib.graph.SignalDrawable; 81 import com.android.settingslib.utils.ThreadUtils; 82 83 import java.util.Arrays; 84 import java.util.List; 85 import java.util.concurrent.ExecutionException; 86 import java.util.concurrent.Future; 87 88 public class MobileNetworkUtils { 89 90 private static final String TAG = "MobileNetworkUtils"; 91 92 // CID of the device. 93 private static final String KEY_CID = "ro.boot.cid"; 94 // CIDs of devices which should not show anything related to eSIM. 95 private static final String KEY_ESIM_CID_IGNORE = "ro.setupwizard.esim_cid_ignore"; 96 // System Property which is used to decide whether the default eSIM UI will be shown, 97 // the default value is false. 98 private static final String KEY_ENABLE_ESIM_UI_BY_DEFAULT = 99 "esim.enable_esim_system_ui_by_default"; 100 private static final String LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT = 101 "android.telecom.action.CONNECTION_SERVICE_CONFIGURE"; 102 103 // The following constants are used to draw signal icon. 104 public static final int NO_CELL_DATA_TYPE_ICON = 0; 105 public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT); 106 107 /** 108 * Returns if DPC APNs are enforced. 109 */ isDpcApnEnforced(Context context)110 public static boolean isDpcApnEnforced(Context context) { 111 try (Cursor enforceCursor = context.getContentResolver().query(ENFORCE_MANAGED_URI, 112 null, null, null, null)) { 113 if (enforceCursor == null || enforceCursor.getCount() != 1) { 114 return false; 115 } 116 enforceCursor.moveToFirst(); 117 return enforceCursor.getInt(0) > 0; 118 } 119 } 120 121 /** 122 * Returns true if Wifi calling is provisioned for the specific subscription with id 123 * {@code subId}. 124 */ 125 @VisibleForTesting isWfcProvisionedOnDevice(int subId)126 public static boolean isWfcProvisionedOnDevice(int subId) { 127 final ProvisioningManager provisioningMgr = 128 ProvisioningManager.createForSubscriptionId(subId); 129 if (provisioningMgr == null) { 130 return true; 131 } 132 return provisioningMgr.getProvisioningStatusForCapability( 133 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 134 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 135 } 136 137 /** 138 * @return The current user setting for whether or not contact discovery is enabled for the 139 * subscription id specified. 140 * @see RcsUceAdapter#isUceSettingEnabled() 141 */ isContactDiscoveryEnabled(Context context, int subId)142 public static boolean isContactDiscoveryEnabled(Context context, int subId) { 143 ImsManager imsManager = 144 context.getSystemService(ImsManager.class); 145 return isContactDiscoveryEnabled(imsManager, subId); 146 } 147 148 /** 149 * @return The current user setting for whether or not contact discovery is enabled for the 150 * subscription id specified. 151 * @see RcsUceAdapter#isUceSettingEnabled() 152 */ isContactDiscoveryEnabled(ImsManager imsManager, int subId)153 public static boolean isContactDiscoveryEnabled(ImsManager imsManager, 154 int subId) { 155 ImsRcsManager manager = getImsRcsManager(imsManager, subId); 156 if (manager == null) return false; 157 RcsUceAdapter adapter = manager.getUceAdapter(); 158 try { 159 return adapter.isUceSettingEnabled(); 160 } catch (android.telephony.ims.ImsException e) { 161 Log.w(TAG, "UCE service is not available: " + e.getMessage()); 162 } 163 return false; 164 } 165 166 /** 167 * Set the new user setting to enable or disable contact discovery through RCS UCE. 168 * @see RcsUceAdapter#setUceSettingEnabled(boolean) 169 */ setContactDiscoveryEnabled(ImsManager imsManager, int subId, boolean isEnabled)170 public static void setContactDiscoveryEnabled(ImsManager imsManager, 171 int subId, boolean isEnabled) { 172 ImsRcsManager manager = getImsRcsManager(imsManager, subId); 173 if (manager == null) return; 174 RcsUceAdapter adapter = manager.getUceAdapter(); 175 try { 176 adapter.setUceSettingEnabled(isEnabled); 177 } catch (android.telephony.ims.ImsException e) { 178 Log.w(TAG, "UCE service is not available: " + e.getMessage()); 179 } 180 } 181 182 /** 183 * @return The ImsRcsManager associated with the subscription specified. 184 */ getImsRcsManager(ImsManager imsManager, int subId)185 private static ImsRcsManager getImsRcsManager(ImsManager imsManager, 186 int subId) { 187 if (imsManager == null) return null; 188 try { 189 return imsManager.getImsRcsManager(subId); 190 } catch (Exception e) { 191 Log.w(TAG, "Could not resolve ImsRcsManager: " + e.getMessage()); 192 } 193 return null; 194 } 195 196 /** 197 * @return true if contact discovery is available for the subscription specified and the option 198 * should be shown to the user, false if the option should be hidden. 199 */ isContactDiscoveryVisible(Context context, int subId)200 public static boolean isContactDiscoveryVisible(Context context, int subId) { 201 CarrierConfigManager carrierConfigManager = context.getSystemService( 202 CarrierConfigManager.class); 203 if (carrierConfigManager == null) { 204 Log.w(TAG, "isContactDiscoveryVisible: Could not resolve carrier config"); 205 return false; 206 } 207 PersistableBundle bundle = carrierConfigManager.getConfigForSubId(subId); 208 return bundle.getBoolean( 209 CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, false /*default*/) 210 || bundle.getBoolean(CarrierConfigManager.Ims.KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, 211 false /*default*/); 212 } 213 buildPhoneAccountConfigureIntent( Context context, PhoneAccountHandle accountHandle)214 public static Intent buildPhoneAccountConfigureIntent( 215 Context context, PhoneAccountHandle accountHandle) { 216 Intent intent = buildConfigureIntent( 217 context, accountHandle, TelecomManager.ACTION_CONFIGURE_PHONE_ACCOUNT); 218 219 if (intent == null) { 220 // If the new configuration didn't work, try the old configuration intent. 221 intent = buildConfigureIntent(context, accountHandle, 222 LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT); 223 } 224 return intent; 225 } 226 buildConfigureIntent( Context context, PhoneAccountHandle accountHandle, String actionStr)227 private static Intent buildConfigureIntent( 228 Context context, PhoneAccountHandle accountHandle, String actionStr) { 229 if (accountHandle == null || accountHandle.getComponentName() == null 230 || TextUtils.isEmpty(accountHandle.getComponentName().getPackageName())) { 231 return null; 232 } 233 234 // Build the settings intent. 235 Intent intent = new Intent(actionStr); 236 intent.setPackage(accountHandle.getComponentName().getPackageName()); 237 intent.addCategory(Intent.CATEGORY_DEFAULT); 238 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 239 240 // Check to see that the phone account package can handle the setting intent. 241 final PackageManager pm = context.getPackageManager(); 242 final List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0); 243 if (resolutions.size() == 0) { 244 intent = null; // set no intent if the package cannot handle it. 245 } 246 247 return intent; 248 } 249 250 /** 251 * Whether to show the entry point to eUICC settings. 252 * 253 * <p>We show the entry point on any device which supports eUICC as long as either the eUICC 254 * was ever provisioned (that is, at least one profile was ever downloaded onto it), or if 255 * the user has enabled development mode. 256 */ showEuiccSettings(Context context)257 public static boolean showEuiccSettings(Context context) { 258 long timeForAccess = SystemClock.elapsedRealtime(); 259 try { 260 return ((Future<Boolean>) ThreadUtils.postOnBackgroundThread(() 261 -> showEuiccSettingsDetecting(context))).get(); 262 } catch (ExecutionException | InterruptedException exception) { 263 timeForAccess = SystemClock.elapsedRealtime() - timeForAccess; 264 Log.w(TAG, "Accessing Euicc takes too long: +" + timeForAccess + "ms"); 265 } 266 return false; 267 } 268 269 // The same as #showEuiccSettings(Context context) showEuiccSettingsDetecting(Context context)270 public static Boolean showEuiccSettingsDetecting(Context context) { 271 final EuiccManager euiccManager = 272 (EuiccManager) context.getSystemService(EuiccManager.class); 273 if (!euiccManager.isEnabled()) { 274 Log.w(TAG, "EuiccManager is not enabled."); 275 return false; 276 } 277 278 final ContentResolver cr = context.getContentResolver(); 279 final boolean esimIgnoredDevice = 280 Arrays.asList(TextUtils.split(SystemProperties.get(KEY_ESIM_CID_IGNORE, ""), ",")) 281 .contains(SystemProperties.get(KEY_CID, null)); 282 final boolean enabledEsimUiByDefault = 283 SystemProperties.getBoolean(KEY_ENABLE_ESIM_UI_BY_DEFAULT, true); 284 final boolean euiccProvisioned = 285 Settings.Global.getInt(cr, Settings.Global.EUICC_PROVISIONED, 0) != 0; 286 final boolean inDeveloperMode = 287 DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context); 288 Log.i(TAG, 289 String.format("showEuiccSettings: esimIgnoredDevice: %b, enabledEsimUiByDefault: " 290 + "%b, euiccProvisioned: %b, inDeveloperMode: %b.", 291 esimIgnoredDevice, enabledEsimUiByDefault, euiccProvisioned, inDeveloperMode)); 292 return (euiccProvisioned 293 || (!esimIgnoredDevice && inDeveloperMode) 294 || (!esimIgnoredDevice && enabledEsimUiByDefault 295 && isCurrentCountrySupported(context))); 296 } 297 298 /** 299 * Return {@code true} if mobile data is enabled 300 */ isMobileDataEnabled(Context context)301 public static boolean isMobileDataEnabled(Context context) { 302 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 303 if (!telephonyManager.isDataEnabled()) { 304 // Check if the data is enabled on the second SIM in the case of dual SIM. 305 final TelephonyManager tmDefaultData = telephonyManager.createForSubscriptionId( 306 SubscriptionManager.getDefaultDataSubscriptionId()); 307 if (tmDefaultData == null || !tmDefaultData.isDataEnabled()) { 308 return false; 309 } 310 } 311 return true; 312 } 313 314 /** 315 * Set whether to enable data for {@code subId}, also whether to disable data for other 316 * subscription 317 */ setMobileDataEnabled(Context context, int subId, boolean enabled, boolean disableOtherSubscriptions)318 public static void setMobileDataEnabled(Context context, int subId, boolean enabled, 319 boolean disableOtherSubscriptions) { 320 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) 321 .createForSubscriptionId(subId); 322 final SubscriptionManager subscriptionManager = context.getSystemService( 323 SubscriptionManager.class); 324 telephonyManager.setDataEnabled(enabled); 325 326 if (disableOtherSubscriptions) { 327 final List<SubscriptionInfo> subInfoList = 328 subscriptionManager.getActiveSubscriptionInfoList(); 329 if (subInfoList != null) { 330 for (SubscriptionInfo subInfo : subInfoList) { 331 // We never disable mobile data for opportunistic subscriptions. 332 if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) { 333 context.getSystemService(TelephonyManager.class).createForSubscriptionId( 334 subInfo.getSubscriptionId()).setDataEnabled(false); 335 } 336 } 337 } 338 } 339 } 340 341 /** 342 * Return {@code true} if show CDMA category 343 */ isCdmaOptions(Context context, int subId)344 public static boolean isCdmaOptions(Context context, int subId) { 345 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 346 return false; 347 } 348 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) 349 .createForSubscriptionId(subId); 350 final PersistableBundle carrierConfig = context.getSystemService( 351 CarrierConfigManager.class).getConfigForSubId(subId); 352 353 354 if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { 355 return true; 356 } else if (carrierConfig != null 357 && !carrierConfig.getBoolean( 358 CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) 359 && carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { 360 return true; 361 } 362 363 if (isWorldMode(context, subId)) { 364 final int settingsNetworkMode = getNetworkTypeFromRaf( 365 (int) telephonyManager.getAllowedNetworkTypesForReason( 366 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER)); 367 368 if (settingsNetworkMode == NETWORK_MODE_LTE_GSM_WCDMA 369 || settingsNetworkMode == NETWORK_MODE_LTE_CDMA_EVDO 370 || settingsNetworkMode == NETWORK_MODE_NR_LTE_GSM_WCDMA 371 || settingsNetworkMode == NETWORK_MODE_NR_LTE_CDMA_EVDO) { 372 return true; 373 } 374 375 if (shouldSpeciallyUpdateGsmCdma(context, subId)) { 376 return true; 377 } 378 } 379 380 return false; 381 } 382 383 /** 384 * return {@code true} if we need show Gsm related settings 385 */ isGsmOptions(Context context, int subId)386 public static boolean isGsmOptions(Context context, int subId) { 387 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 388 return false; 389 } 390 if (isGsmBasicOptions(context, subId)) { 391 return true; 392 } 393 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) 394 .createForSubscriptionId(subId); 395 final int networkMode = getNetworkTypeFromRaf( 396 (int) telephonyManager.getAllowedNetworkTypesForReason( 397 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER)); 398 if (isWorldMode(context, subId)) { 399 if (networkMode == NETWORK_MODE_LTE_CDMA_EVDO 400 || networkMode == NETWORK_MODE_LTE_GSM_WCDMA 401 || networkMode == NETWORK_MODE_NR_LTE_CDMA_EVDO 402 || networkMode == NETWORK_MODE_NR_LTE_GSM_WCDMA) { 403 return true; 404 } else if (shouldSpeciallyUpdateGsmCdma(context, subId)) { 405 return true; 406 } 407 } 408 409 return false; 410 } 411 isGsmBasicOptions(Context context, int subId)412 private static boolean isGsmBasicOptions(Context context, int subId) { 413 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) 414 .createForSubscriptionId(subId); 415 final PersistableBundle carrierConfig = context.getSystemService( 416 CarrierConfigManager.class).getConfigForSubId(subId); 417 418 if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) { 419 return true; 420 } else if (carrierConfig != null 421 && !carrierConfig.getBoolean( 422 CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) 423 && carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { 424 return true; 425 } 426 427 return false; 428 } 429 430 /** 431 * Return {@code true} if it is world mode, and we may show advanced options in telephony 432 * settings 433 */ isWorldMode(Context context, int subId)434 public static boolean isWorldMode(Context context, int subId) { 435 final PersistableBundle carrierConfig = context.getSystemService( 436 CarrierConfigManager.class).getConfigForSubId(subId); 437 return carrierConfig == null 438 ? false 439 : carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL); 440 } 441 442 /** 443 * Return {@code true} if we need show settings for network selection(i.e. Verizon) 444 */ shouldDisplayNetworkSelectOptions(Context context, int subId)445 public static boolean shouldDisplayNetworkSelectOptions(Context context, int subId) { 446 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) 447 .createForSubscriptionId(subId); 448 final PersistableBundle carrierConfig = context.getSystemService( 449 CarrierConfigManager.class).getConfigForSubId(subId); 450 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 451 || carrierConfig == null 452 || !carrierConfig.getBoolean( 453 CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL) 454 || carrierConfig.getBoolean( 455 CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) 456 || (carrierConfig.getBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL) 457 && !telephonyManager.isManualNetworkSelectionAllowed())) { 458 return false; 459 } 460 461 final int networkMode = getNetworkTypeFromRaf( 462 (int) telephonyManager.getAllowedNetworkTypesForReason( 463 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER)); 464 if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO 465 && isWorldMode(context, subId)) { 466 return false; 467 } 468 if (shouldSpeciallyUpdateGsmCdma(context, subId)) { 469 return false; 470 } 471 472 if (isGsmBasicOptions(context, subId)) { 473 return true; 474 } 475 476 if (isWorldMode(context, subId)) { 477 if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA) { 478 return true; 479 } 480 } 481 482 return false; 483 } 484 485 /** 486 * Return {@code true} if Tdscdma is supported in current subscription 487 */ isTdscdmaSupported(Context context, int subId)488 public static boolean isTdscdmaSupported(Context context, int subId) { 489 return isTdscdmaSupported(context, 490 context.getSystemService(TelephonyManager.class).createForSubscriptionId(subId)); 491 } 492 493 //TODO(b/117651939): move it to telephony isTdscdmaSupported(Context context, TelephonyManager telephonyManager)494 private static boolean isTdscdmaSupported(Context context, TelephonyManager telephonyManager) { 495 final PersistableBundle carrierConfig = context.getSystemService( 496 CarrierConfigManager.class).getConfig(); 497 498 if (carrierConfig == null) { 499 return false; 500 } 501 502 if (carrierConfig.getBoolean(CarrierConfigManager.KEY_SUPPORT_TDSCDMA_BOOL)) { 503 return true; 504 } 505 final ServiceState serviceState = telephonyManager.getServiceState(); 506 final String operatorNumeric = 507 (serviceState != null) ? serviceState.getOperatorNumeric() : null; 508 final String[] numericArray = carrierConfig.getStringArray( 509 CarrierConfigManager.KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY); 510 if (numericArray == null || operatorNumeric == null) { 511 return false; 512 } 513 for (String numeric : numericArray) { 514 if (operatorNumeric.equals(numeric)) { 515 return true; 516 } 517 } 518 return false; 519 } 520 521 /** 522 * Return subId that supported by search. If there are more than one, return first one, 523 * otherwise return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} 524 */ getSearchableSubscriptionId(Context context)525 public static int getSearchableSubscriptionId(Context context) { 526 final int[] subIds = getActiveSubscriptionIdList(context); 527 528 return subIds.length >= 1 ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID; 529 } 530 531 /** 532 * Return availability for a default subscription id. If subId already been set, use it to 533 * check, otherwise traverse all active subIds on device to check. 534 * @param context context 535 * @param defSubId Default subId get from telephony preference controller 536 * @param callback Callback to check availability for a specific subId 537 * @return Availability 538 * 539 * @see BasePreferenceController#getAvailabilityStatus() 540 */ getAvailability(Context context, int defSubId, TelephonyAvailabilityCallback callback)541 public static int getAvailability(Context context, int defSubId, 542 TelephonyAvailabilityCallback callback) { 543 if (defSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 544 // If subId has been set, return the corresponding status 545 return callback.getAvailabilityStatus(defSubId); 546 } else { 547 // Otherwise, search whether there is one subId in device that support this preference 548 final int[] subIds = getActiveSubscriptionIdList(context); 549 if (ArrayUtils.isEmpty(subIds)) { 550 return callback.getAvailabilityStatus( 551 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 552 } else { 553 for (final int subId : subIds) { 554 final int status = callback.getAvailabilityStatus(subId); 555 if (status == BasePreferenceController.AVAILABLE) { 556 return status; 557 } 558 } 559 return callback.getAvailabilityStatus(subIds[0]); 560 } 561 } 562 } 563 564 /** 565 * This method is migrated from {@link com.android.phone.MobileNetworkSettings} and we should 566 * use it carefully. This code snippet doesn't have very clear meaning however we should 567 * update GSM or CDMA differently based on what it returns. 568 * 569 * 1. For all CDMA settings, make them visible if it return {@code true} 570 * 2. For GSM settings, make them visible if it return {@code true} unless 3 571 * 3. For network select settings, make it invisible if it return {@code true} 572 */ 573 @VisibleForTesting shouldSpeciallyUpdateGsmCdma(Context context, int subId)574 static boolean shouldSpeciallyUpdateGsmCdma(Context context, int subId) { 575 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) 576 .createForSubscriptionId(subId); 577 final int networkMode = getNetworkTypeFromRaf( 578 (int) telephonyManager.getAllowedNetworkTypesForReason( 579 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER)); 580 if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM 581 || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA 582 || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA 583 || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA 584 || networkMode 585 == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA 586 || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA) { 587 if (!isTdscdmaSupported(context, subId) && isWorldMode(context, subId)) { 588 return true; 589 } 590 } 591 592 return false; 593 } 594 getSignalStrengthIcon(Context context, int level, int numLevels, int iconType, boolean cutOut)595 public static Drawable getSignalStrengthIcon(Context context, int level, int numLevels, 596 int iconType, boolean cutOut) { 597 final SignalDrawable signalDrawable = new SignalDrawable(context); 598 signalDrawable.setLevel( 599 SignalDrawable.getState(level, numLevels, cutOut)); 600 601 // Make the network type drawable 602 final Drawable networkDrawable = 603 iconType == NO_CELL_DATA_TYPE_ICON 604 ? EMPTY_DRAWABLE 605 : context.getResources().getDrawable(iconType, context.getTheme()); 606 607 // Overlay the two drawables 608 final Drawable[] layers = {networkDrawable, signalDrawable}; 609 final int iconSize = 610 context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size); 611 612 final LayerDrawable icons = new LayerDrawable(layers); 613 // Set the network type icon at the top left 614 icons.setLayerGravity(0 /* index of networkDrawable */, Gravity.TOP | Gravity.LEFT); 615 // Set the signal strength icon at the bottom right 616 icons.setLayerGravity(1 /* index of SignalDrawable */, Gravity.BOTTOM | Gravity.RIGHT); 617 icons.setLayerSize(1 /* index of SignalDrawable */, iconSize, iconSize); 618 icons.setTintList(Utils.getColorAttr(context, android.R.attr.colorControlNormal)); 619 return icons; 620 } 621 622 /** 623 * This method is migrated from 624 * {@link android.telephony.TelephonyManager.getNetworkOperatorName}. Which provides 625 * 626 * 1. Better support under multi-SIM environment. 627 * 2. Similar design which aligned with operator name displayed in status bar 628 */ getCurrentCarrierNameForDisplay(Context context, int subId)629 public static CharSequence getCurrentCarrierNameForDisplay(Context context, int subId) { 630 final SubscriptionManager sm = context.getSystemService(SubscriptionManager.class); 631 if (sm != null) { 632 final SubscriptionInfo subInfo = getSubscriptionInfo(sm, subId); 633 if (subInfo != null) { 634 return subInfo.getCarrierName(); 635 } 636 } 637 return getOperatorNameFromTelephonyManager(context); 638 } 639 getCurrentCarrierNameForDisplay(Context context)640 public static CharSequence getCurrentCarrierNameForDisplay(Context context) { 641 final SubscriptionManager sm = context.getSystemService(SubscriptionManager.class); 642 if (sm != null) { 643 final int subId = sm.getDefaultSubscriptionId(); 644 final SubscriptionInfo subInfo = getSubscriptionInfo(sm, subId); 645 if (subInfo != null) { 646 return subInfo.getCarrierName(); 647 } 648 } 649 return getOperatorNameFromTelephonyManager(context); 650 } 651 getSubscriptionInfo(SubscriptionManager subManager, int subId)652 private static SubscriptionInfo getSubscriptionInfo(SubscriptionManager subManager, int subId) { 653 List<SubscriptionInfo> subInfos = subManager.getActiveSubscriptionInfoList(); 654 if (subInfos == null) { 655 return null; 656 } 657 for (SubscriptionInfo subInfo : subInfos) { 658 if (subInfo.getSubscriptionId() == subId) { 659 return subInfo; 660 } 661 } 662 return null; 663 } 664 getOperatorNameFromTelephonyManager(Context context)665 private static String getOperatorNameFromTelephonyManager(Context context) { 666 final TelephonyManager tm = 667 (TelephonyManager) context.getSystemService(TelephonyManager.class); 668 if (tm == null) { 669 return null; 670 } 671 return tm.getNetworkOperatorName(); 672 } 673 getActiveSubscriptionIdList(Context context)674 private static int[] getActiveSubscriptionIdList(Context context) { 675 final SubscriptionManager subscriptionManager = context.getSystemService( 676 SubscriptionManager.class); 677 final List<SubscriptionInfo> subInfoList = 678 subscriptionManager.getActiveSubscriptionInfoList(); 679 if (subInfoList == null) { 680 return new int[0]; 681 } 682 int[] activeSubIds = new int[subInfoList.size()]; 683 int i = 0; 684 for (SubscriptionInfo subInfo : subInfoList) { 685 activeSubIds[i] = subInfo.getSubscriptionId(); 686 i++; 687 } 688 return activeSubIds; 689 } 690 691 /** 692 * Loop through all the device logical slots to check whether the user's current country 693 * supports eSIM. 694 */ isCurrentCountrySupported(Context context)695 private static boolean isCurrentCountrySupported(Context context) { 696 final EuiccManager em = (EuiccManager) context.getSystemService(EuiccManager.class); 697 final TelephonyManager tm = 698 (TelephonyManager) context.getSystemService(TelephonyManager.class); 699 700 for (int i = 0; i < tm.getPhoneCount(); i++) { 701 String countryCode = tm.getNetworkCountryIso(i); 702 if (em.isSupportedCountry(countryCode)) { 703 Log.i(TAG, "isCurrentCountrySupported: eSIM is supported in " + countryCode); 704 return true; 705 } 706 } 707 Log.i(TAG, "isCurrentCountrySupported: eSIM is not supported in the current country."); 708 return false; 709 } 710 711 /** 712 * Imported from {@link android.telephony.RadioAccessFamily} 713 */ getRafFromNetworkType(int type)714 public static long getRafFromNetworkType(int type) { 715 switch (type) { 716 case TelephonyManagerConstants.NETWORK_MODE_WCDMA_PREF: 717 return GSM | WCDMA; 718 case TelephonyManagerConstants.NETWORK_MODE_GSM_ONLY: 719 return GSM; 720 case TelephonyManagerConstants.NETWORK_MODE_WCDMA_ONLY: 721 return WCDMA; 722 case TelephonyManagerConstants.NETWORK_MODE_GSM_UMTS: 723 return GSM | WCDMA; 724 case TelephonyManagerConstants.NETWORK_MODE_CDMA_EVDO: 725 return CDMA | EVDO; 726 case TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO: 727 return LTE | CDMA | EVDO; 728 case TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA: 729 return LTE | GSM | WCDMA; 730 case TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA: 731 return LTE | CDMA | EVDO | GSM | WCDMA; 732 case TelephonyManagerConstants.NETWORK_MODE_LTE_ONLY: 733 return LTE; 734 case TelephonyManagerConstants.NETWORK_MODE_LTE_WCDMA: 735 return LTE | WCDMA; 736 case TelephonyManagerConstants.NETWORK_MODE_CDMA_NO_EVDO: 737 return CDMA; 738 case TelephonyManagerConstants.NETWORK_MODE_EVDO_NO_CDMA: 739 return EVDO; 740 case TelephonyManagerConstants.NETWORK_MODE_GLOBAL: 741 return GSM | WCDMA | CDMA | EVDO; 742 case TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_ONLY: 743 return RAF_TD_SCDMA; 744 case TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_WCDMA: 745 return RAF_TD_SCDMA | WCDMA; 746 case TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA: 747 return LTE | RAF_TD_SCDMA; 748 case TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_GSM: 749 return RAF_TD_SCDMA | GSM; 750 case TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM: 751 return LTE | RAF_TD_SCDMA | GSM; 752 case TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA: 753 return RAF_TD_SCDMA | GSM | WCDMA; 754 case TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA: 755 return LTE | RAF_TD_SCDMA | WCDMA; 756 case TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA: 757 return LTE | RAF_TD_SCDMA | GSM | WCDMA; 758 case TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA: 759 return RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA; 760 case TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA: 761 return LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA; 762 case (TelephonyManagerConstants.NETWORK_MODE_NR_ONLY): 763 return NR; 764 case (TelephonyManagerConstants.NETWORK_MODE_NR_LTE): 765 return NR | LTE; 766 case (TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO): 767 return NR | LTE | CDMA | EVDO; 768 case (TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA): 769 return NR | LTE | GSM | WCDMA; 770 case (TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA): 771 return NR | LTE | CDMA | EVDO | GSM | WCDMA; 772 case (TelephonyManagerConstants.NETWORK_MODE_NR_LTE_WCDMA): 773 return NR | LTE | WCDMA; 774 case (TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA): 775 return NR | LTE | RAF_TD_SCDMA; 776 case (TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM): 777 return NR | LTE | RAF_TD_SCDMA | GSM; 778 case (TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA): 779 return NR | LTE | RAF_TD_SCDMA | WCDMA; 780 case (TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA): 781 return NR | LTE | RAF_TD_SCDMA | GSM | WCDMA; 782 case (TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA): 783 return NR | LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA; 784 default: 785 return RAF_UNKNOWN; 786 } 787 } 788 789 /** 790 * Imported from {@link android.telephony.RadioAccessFamily} 791 */ getNetworkTypeFromRaf(int raf)792 public static int getNetworkTypeFromRaf(int raf) { 793 raf = getAdjustedRaf(raf); 794 795 switch (raf) { 796 case (GSM | WCDMA): 797 return TelephonyManagerConstants.NETWORK_MODE_WCDMA_PREF; 798 case GSM: 799 return TelephonyManagerConstants.NETWORK_MODE_GSM_ONLY; 800 case WCDMA: 801 return TelephonyManagerConstants.NETWORK_MODE_WCDMA_ONLY; 802 case (CDMA | EVDO): 803 return TelephonyManagerConstants.NETWORK_MODE_CDMA_EVDO; 804 case (LTE | CDMA | EVDO): 805 return TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO; 806 case (LTE | GSM | WCDMA): 807 return TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA; 808 case (LTE | CDMA | EVDO | GSM | WCDMA): 809 return TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA; 810 case LTE: 811 return TelephonyManagerConstants.NETWORK_MODE_LTE_ONLY; 812 case (LTE | WCDMA): 813 return TelephonyManagerConstants.NETWORK_MODE_LTE_WCDMA; 814 case CDMA: 815 return TelephonyManagerConstants.NETWORK_MODE_CDMA_NO_EVDO; 816 case EVDO: 817 return TelephonyManagerConstants.NETWORK_MODE_EVDO_NO_CDMA; 818 case (GSM | WCDMA | CDMA | EVDO): 819 return TelephonyManagerConstants.NETWORK_MODE_GLOBAL; 820 case RAF_TD_SCDMA: 821 return TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_ONLY; 822 case (RAF_TD_SCDMA | WCDMA): 823 return TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_WCDMA; 824 case (LTE | RAF_TD_SCDMA): 825 return TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA; 826 case (RAF_TD_SCDMA | GSM): 827 return TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_GSM; 828 case (LTE | RAF_TD_SCDMA | GSM): 829 return TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM; 830 case (RAF_TD_SCDMA | GSM | WCDMA): 831 return TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA; 832 case (LTE | RAF_TD_SCDMA | WCDMA): 833 return TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA; 834 case (LTE | RAF_TD_SCDMA | GSM | WCDMA): 835 return TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA; 836 case (RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA): 837 return TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; 838 case (LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA): 839 return TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; 840 case (NR): 841 return TelephonyManagerConstants.NETWORK_MODE_NR_ONLY; 842 case (NR | LTE): 843 return TelephonyManagerConstants.NETWORK_MODE_NR_LTE; 844 case (NR | LTE | CDMA | EVDO): 845 return TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO; 846 case (NR | LTE | GSM | WCDMA): 847 return TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA; 848 case (NR | LTE | CDMA | EVDO | GSM | WCDMA): 849 return TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA; 850 case (NR | LTE | WCDMA): 851 return TelephonyManagerConstants.NETWORK_MODE_NR_LTE_WCDMA; 852 case (NR | LTE | RAF_TD_SCDMA): 853 return TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA; 854 case (NR | LTE | RAF_TD_SCDMA | GSM): 855 return TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM; 856 case (NR | LTE | RAF_TD_SCDMA | WCDMA): 857 return TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA; 858 case (NR | LTE | RAF_TD_SCDMA | GSM | WCDMA): 859 return TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA; 860 case (NR | LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA): 861 return TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; 862 default: 863 return TelephonyManagerConstants.NETWORK_MODE_UNKNOWN; 864 } 865 } 866 867 /** 868 * Imported from {@link android.telephony.RadioAccessFamily} 869 */ getAdjustedRaf(int raf)870 private static int getAdjustedRaf(int raf) { 871 raf = ((GSM & raf) > 0) ? (GSM | raf) : raf; 872 raf = ((WCDMA & raf) > 0) ? (WCDMA | raf) : raf; 873 raf = ((CDMA & raf) > 0) ? (CDMA | raf) : raf; 874 raf = ((EVDO & raf) > 0) ? (EVDO | raf) : raf; 875 raf = ((LTE & raf) > 0) ? (LTE | raf) : raf; 876 raf = ((NR & raf) > 0) ? (NR | raf) : raf; 877 return raf; 878 } 879 880 /** 881 * Copied from SubscriptionsPreferenceController#activeNetworkIsCellular() 882 */ activeNetworkIsCellular(Context context)883 public static boolean activeNetworkIsCellular(Context context) { 884 final ConnectivityManager connectivityManager = 885 context.getSystemService(ConnectivityManager.class); 886 final Network activeNetwork = connectivityManager.getActiveNetwork(); 887 if (activeNetwork == null) { 888 return false; 889 } 890 final NetworkCapabilities networkCapabilities = 891 connectivityManager.getNetworkCapabilities(activeNetwork); 892 if (networkCapabilities == null) { 893 return false; 894 } 895 return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); 896 } 897 898 /** 899 * Copied from WifiCallingPreferenceController#isWifiCallingEnabled() 900 */ isWifiCallingEnabled(Context context, int subId, @Nullable WifiCallingQueryImsState queryImsState, @Nullable PhoneAccountHandle phoneAccountHandle)901 public static boolean isWifiCallingEnabled(Context context, int subId, 902 @Nullable WifiCallingQueryImsState queryImsState, 903 @Nullable PhoneAccountHandle phoneAccountHandle) { 904 if (phoneAccountHandle == null){ 905 phoneAccountHandle = context.getSystemService(TelecomManager.class) 906 .getSimCallManagerForSubscription(subId); 907 } 908 boolean isWifiCallingEnabled; 909 if (phoneAccountHandle != null) { 910 final Intent intent = buildPhoneAccountConfigureIntent(context, phoneAccountHandle); 911 isWifiCallingEnabled = intent != null; 912 } else { 913 if (queryImsState == null) { 914 queryImsState = new WifiCallingQueryImsState(context, subId); 915 } 916 isWifiCallingEnabled = queryImsState.isReadyToWifiCalling(); 917 } 918 return isWifiCallingEnabled; 919 } 920 921 922 /** 923 * Returns preferred status of Calls & SMS separately when Provider Model is enabled. 924 */ getPreferredStatus(Context context, SubscriptionManager subscriptionManager, boolean isPreferredCallStatus)925 public static CharSequence getPreferredStatus(Context context, 926 SubscriptionManager subscriptionManager, boolean isPreferredCallStatus) { 927 final List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions( 928 subscriptionManager); 929 if (!subs.isEmpty()) { 930 final StringBuilder summary = new StringBuilder(); 931 for (SubscriptionInfo subInfo : subs) { 932 int subsSize = subs.size(); 933 final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName( 934 subInfo, context); 935 936 // Set displayName as summary if there is only one valid SIM. 937 if (subsSize == 1 938 && SubscriptionManager.isValidSubscriptionId(subInfo.getSubscriptionId())) { 939 return displayName; 940 } 941 942 CharSequence status = isPreferredCallStatus 943 ? getPreferredCallStatus(context, subInfo) 944 : getPreferredSmsStatus(context, subInfo); 945 if (status.toString().isEmpty()) { 946 // If there are 2 or more SIMs and one of these has no preferred status, 947 // set only its displayName as summary. 948 summary.append(displayName); 949 } else { 950 summary.append(displayName) 951 .append(" (") 952 .append(status) 953 .append(")"); 954 } 955 // Do not add ", " for the last subscription. 956 if (subInfo != subs.get(subs.size() - 1)) { 957 summary.append(", "); 958 } 959 } 960 return summary; 961 } else { 962 return ""; 963 } 964 } 965 getPreferredCallStatus(Context context, SubscriptionInfo subInfo)966 private static CharSequence getPreferredCallStatus(Context context, SubscriptionInfo subInfo) { 967 final int subId = subInfo.getSubscriptionId(); 968 String status = ""; 969 boolean isDataPreferred = subId == SubscriptionManager.getDefaultVoiceSubscriptionId(); 970 971 if (isDataPreferred) { 972 status = setSummaryResId(context, R.string.calls_sms_preferred); 973 } 974 975 return status; 976 } 977 getPreferredSmsStatus(Context context, SubscriptionInfo subInfo)978 private static CharSequence getPreferredSmsStatus(Context context, SubscriptionInfo subInfo) { 979 final int subId = subInfo.getSubscriptionId(); 980 String status = ""; 981 boolean isSmsPreferred = subId == SubscriptionManager.getDefaultSmsSubscriptionId(); 982 983 if (isSmsPreferred) { 984 status = setSummaryResId(context, R.string.calls_sms_preferred); 985 } 986 987 return status; 988 } 989 setSummaryResId(Context context, int resId)990 private static String setSummaryResId(Context context, int resId) { 991 return context.getResources().getString(resId); 992 } 993 994 } 995