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 android.content.ContentResolver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.pm.PackageManager; 25 import android.content.pm.ResolveInfo; 26 import android.database.Cursor; 27 import android.graphics.Color; 28 import android.graphics.drawable.ColorDrawable; 29 import android.graphics.drawable.Drawable; 30 import android.graphics.drawable.LayerDrawable; 31 import android.os.PersistableBundle; 32 import android.os.SystemProperties; 33 import android.provider.Settings; 34 import android.telecom.PhoneAccountHandle; 35 import android.telecom.TelecomManager; 36 import android.telephony.CarrierConfigManager; 37 import android.telephony.SubscriptionInfo; 38 import android.telephony.SubscriptionManager; 39 import android.telephony.TelephonyManager; 40 import android.telephony.euicc.EuiccManager; 41 import android.telephony.ims.ImsRcsManager; 42 import android.telephony.ims.ProvisioningManager; 43 import android.telephony.ims.RcsUceAdapter; 44 import android.telephony.ims.feature.ImsFeature; 45 import android.telephony.ims.feature.MmTelFeature; 46 import android.telephony.ims.stub.ImsRegistrationImplBase; 47 import android.text.TextUtils; 48 import android.util.Log; 49 import android.view.Gravity; 50 51 import androidx.annotation.VisibleForTesting; 52 53 import com.android.ims.ImsException; 54 import com.android.ims.ImsManager; 55 import com.android.internal.telephony.Phone; 56 import com.android.internal.telephony.PhoneConstants; 57 import com.android.internal.util.ArrayUtils; 58 import com.android.settings.R; 59 import com.android.settings.Utils; 60 import com.android.settings.core.BasePreferenceController; 61 import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants; 62 import com.android.settingslib.development.DevelopmentSettingsEnabler; 63 import com.android.settingslib.graph.SignalDrawable; 64 65 import java.util.Arrays; 66 import java.util.List; 67 68 public class MobileNetworkUtils { 69 70 private static final String TAG = "MobileNetworkUtils"; 71 72 // CID of the device. 73 private static final String KEY_CID = "ro.boot.cid"; 74 // CIDs of devices which should not show anything related to eSIM. 75 private static final String KEY_ESIM_CID_IGNORE = "ro.setupwizard.esim_cid_ignore"; 76 // System Property which is used to decide whether the default eSIM UI will be shown, 77 // the default value is false. 78 private static final String KEY_ENABLE_ESIM_UI_BY_DEFAULT = 79 "esim.enable_esim_system_ui_by_default"; 80 private static final String LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT = 81 "android.telecom.action.CONNECTION_SERVICE_CONFIGURE"; 82 83 // The following constants are used to draw signal icon. 84 public static final int NO_CELL_DATA_TYPE_ICON = 0; 85 public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT); 86 87 /** 88 * Returns if DPC APNs are enforced. 89 */ isDpcApnEnforced(Context context)90 public static boolean isDpcApnEnforced(Context context) { 91 try (Cursor enforceCursor = context.getContentResolver().query(ENFORCE_MANAGED_URI, 92 null, null, null, null)) { 93 if (enforceCursor == null || enforceCursor.getCount() != 1) { 94 return false; 95 } 96 enforceCursor.moveToFirst(); 97 return enforceCursor.getInt(0) > 0; 98 } 99 } 100 101 /** 102 * Returns true if Wifi calling is enabled for at least one subscription. 103 */ isWifiCallingEnabled(Context context)104 public static boolean isWifiCallingEnabled(Context context) { 105 final int[] subIds = getActiveSubscriptionIdList(context); 106 if (ArrayUtils.isEmpty(subIds)) { 107 Log.d(TAG, "isWifiCallingEnabled: subIds is empty"); 108 return false; 109 } 110 for (int subId : subIds) { 111 if (isWifiCallingEnabled(context, subId)) { 112 return true; 113 } 114 } 115 return false; 116 } 117 118 /** 119 * Returns true if Wifi calling is provisioned for the specific subscription with id 120 * {@code subId}. 121 */ 122 @VisibleForTesting isWfcProvisionedOnDevice(int subId)123 public static boolean isWfcProvisionedOnDevice(int subId) { 124 final ProvisioningManager provisioningMgr = 125 ProvisioningManager.createForSubscriptionId(subId); 126 if (provisioningMgr == null) { 127 return true; 128 } 129 return provisioningMgr.getProvisioningStatusForCapability( 130 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 131 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 132 } 133 134 /** 135 * Returns true if Wifi calling is enabled for the specific subscription with id {@code subId}. 136 */ isWifiCallingEnabled(Context context, int subId)137 public static boolean isWifiCallingEnabled(Context context, int subId) { 138 final PhoneAccountHandle simCallManager = 139 context.getSystemService(TelecomManager.class) 140 .getSimCallManagerForSubscription(subId); 141 final int phoneId = SubscriptionManager.getSlotIndex(subId); 142 143 boolean isWifiCallingEnabled; 144 if (simCallManager != null) { 145 final Intent intent = buildPhoneAccountConfigureIntent( 146 context, simCallManager); 147 148 isWifiCallingEnabled = intent != null; 149 } else { 150 final ImsManager imsMgr = ImsManager.getInstance(context, phoneId); 151 isWifiCallingEnabled = imsMgr != null 152 && imsMgr.isWfcEnabledByPlatform() 153 && isWfcProvisionedOnDevice(subId) 154 && isImsServiceStateReady(imsMgr); 155 } 156 157 return isWifiCallingEnabled; 158 } 159 160 /** 161 * @return The current user setting for whether or not contact discovery is enabled for the 162 * subscription id specified. 163 * @see RcsUceAdapter#isUceSettingEnabled() 164 */ isContactDiscoveryEnabled(Context context, int subId)165 public static boolean isContactDiscoveryEnabled(Context context, int subId) { 166 android.telephony.ims.ImsManager imsManager = 167 context.getSystemService(android.telephony.ims.ImsManager.class); 168 return isContactDiscoveryEnabled(imsManager, subId); 169 } 170 171 /** 172 * @return The current user setting for whether or not contact discovery is enabled for the 173 * subscription id specified. 174 * @see RcsUceAdapter#isUceSettingEnabled() 175 */ isContactDiscoveryEnabled(android.telephony.ims.ImsManager imsManager, int subId)176 public static boolean isContactDiscoveryEnabled(android.telephony.ims.ImsManager imsManager, 177 int subId) { 178 ImsRcsManager manager = getImsRcsManager(imsManager, subId); 179 if (manager == null) return false; 180 RcsUceAdapter adapter = manager.getUceAdapter(); 181 try { 182 return adapter.isUceSettingEnabled(); 183 } catch (android.telephony.ims.ImsException e) { 184 Log.w(TAG, "UCE service is not available: " + e.getMessage()); 185 } 186 return false; 187 } 188 189 /** 190 * Set the new user setting to enable or disable contact discovery through RCS UCE. 191 * @see RcsUceAdapter#setUceSettingEnabled(boolean) 192 */ setContactDiscoveryEnabled(android.telephony.ims.ImsManager imsManager, int subId, boolean isEnabled)193 public static void setContactDiscoveryEnabled(android.telephony.ims.ImsManager imsManager, 194 int subId, boolean isEnabled) { 195 ImsRcsManager manager = getImsRcsManager(imsManager, subId); 196 if (manager == null) return; 197 RcsUceAdapter adapter = manager.getUceAdapter(); 198 try { 199 adapter.setUceSettingEnabled(isEnabled); 200 } catch (android.telephony.ims.ImsException e) { 201 Log.w(TAG, "UCE service is not available: " + e.getMessage()); 202 } 203 } 204 205 /** 206 * @return The ImsRcsManager associated with the subscription specified. 207 */ getImsRcsManager(android.telephony.ims.ImsManager imsManager, int subId)208 private static ImsRcsManager getImsRcsManager(android.telephony.ims.ImsManager imsManager, 209 int subId) { 210 if (imsManager == null) return null; 211 try { 212 return imsManager.getImsRcsManager(subId); 213 } catch (Exception e) { 214 Log.w(TAG, "Could not resolve ImsRcsManager: " + e.getMessage()); 215 } 216 return null; 217 } 218 219 /** 220 * @return true if contact discovery is available for the subscription specified and the option 221 * should be shown to the user, false if the option should be hidden. 222 */ isContactDiscoveryVisible(Context context, int subId)223 public static boolean isContactDiscoveryVisible(Context context, int subId) { 224 CarrierConfigManager carrierConfigManager = context.getSystemService( 225 CarrierConfigManager.class); 226 if (carrierConfigManager == null) { 227 Log.w(TAG, "isContactDiscoveryVisible: Could not resolve carrier config"); 228 return false; 229 } 230 PersistableBundle bundle = carrierConfigManager.getConfigForSubId(subId); 231 return bundle.getBoolean(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, false /*default*/); 232 } 233 234 @VisibleForTesting buildPhoneAccountConfigureIntent( Context context, PhoneAccountHandle accountHandle)235 static Intent buildPhoneAccountConfigureIntent( 236 Context context, PhoneAccountHandle accountHandle) { 237 Intent intent = buildConfigureIntent( 238 context, accountHandle, TelecomManager.ACTION_CONFIGURE_PHONE_ACCOUNT); 239 240 if (intent == null) { 241 // If the new configuration didn't work, try the old configuration intent. 242 intent = buildConfigureIntent(context, accountHandle, 243 LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT); 244 } 245 return intent; 246 } 247 buildConfigureIntent( Context context, PhoneAccountHandle accountHandle, String actionStr)248 private static Intent buildConfigureIntent( 249 Context context, PhoneAccountHandle accountHandle, String actionStr) { 250 if (accountHandle == null || accountHandle.getComponentName() == null 251 || TextUtils.isEmpty(accountHandle.getComponentName().getPackageName())) { 252 return null; 253 } 254 255 // Build the settings intent. 256 Intent intent = new Intent(actionStr); 257 intent.setPackage(accountHandle.getComponentName().getPackageName()); 258 intent.addCategory(Intent.CATEGORY_DEFAULT); 259 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 260 261 // Check to see that the phone account package can handle the setting intent. 262 final PackageManager pm = context.getPackageManager(); 263 final List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0); 264 if (resolutions.size() == 0) { 265 intent = null; // set no intent if the package cannot handle it. 266 } 267 268 return intent; 269 } 270 isImsServiceStateReady(ImsManager imsMgr)271 public static boolean isImsServiceStateReady(ImsManager imsMgr) { 272 boolean isImsServiceStateReady = false; 273 274 try { 275 if (imsMgr != null && imsMgr.getImsServiceState() == ImsFeature.STATE_READY) { 276 isImsServiceStateReady = true; 277 } 278 } catch (ImsException ex) { 279 Log.e(TAG, "Exception when trying to get ImsServiceStatus: " + ex); 280 } 281 282 Log.d(TAG, "isImsServiceStateReady=" + isImsServiceStateReady); 283 return isImsServiceStateReady; 284 } 285 286 /** 287 * Whether to show the entry point to eUICC settings. 288 * 289 * <p>We show the entry point on any device which supports eUICC as long as either the eUICC 290 * was ever provisioned (that is, at least one profile was ever downloaded onto it), or if 291 * the user has enabled development mode. 292 */ showEuiccSettings(Context context)293 public static boolean showEuiccSettings(Context context) { 294 final EuiccManager euiccManager = 295 (EuiccManager) context.getSystemService(EuiccManager.class); 296 if (!euiccManager.isEnabled()) { 297 return false; 298 } 299 300 final ContentResolver cr = context.getContentResolver(); 301 302 final TelephonyManager tm = 303 (TelephonyManager) context.getSystemService(TelephonyManager.class); 304 final String currentCountry = tm.getNetworkCountryIso().toLowerCase(); 305 final String supportedCountries = 306 Settings.Global.getString(cr, Settings.Global.EUICC_SUPPORTED_COUNTRIES); 307 final String unsupportedCountries = 308 Settings.Global.getString(cr, Settings.Global.EUICC_UNSUPPORTED_COUNTRIES); 309 310 boolean inEsimSupportedCountries = false; 311 312 if (TextUtils.isEmpty(supportedCountries)) { 313 // White list is empty, use blacklist. 314 Log.d(TAG, "Using blacklist unsupportedCountries=" + unsupportedCountries); 315 inEsimSupportedCountries = !isEsimUnsupportedCountry(currentCountry, 316 unsupportedCountries); 317 } else { 318 Log.d(TAG, "Using whitelist supportedCountries=" + supportedCountries); 319 inEsimSupportedCountries = isEsimSupportedCountry(currentCountry, supportedCountries); 320 } 321 322 Log.d(TAG, "inEsimSupportedCountries=" + inEsimSupportedCountries); 323 324 final boolean esimIgnoredDevice = 325 Arrays.asList(TextUtils.split(SystemProperties.get(KEY_ESIM_CID_IGNORE, ""), ",")) 326 .contains(SystemProperties.get(KEY_CID, null)); 327 final boolean enabledEsimUiByDefault = 328 SystemProperties.getBoolean(KEY_ENABLE_ESIM_UI_BY_DEFAULT, true); 329 final boolean euiccProvisioned = 330 Settings.Global.getInt(cr, Settings.Global.EUICC_PROVISIONED, 0) != 0; 331 final boolean inDeveloperMode = 332 DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context); 333 334 return (inDeveloperMode || euiccProvisioned 335 || (!esimIgnoredDevice && enabledEsimUiByDefault && inEsimSupportedCountries)); 336 } 337 338 /** 339 * Set whether to enable data for {@code subId}, also whether to disable data for other 340 * subscription 341 */ setMobileDataEnabled(Context context, int subId, boolean enabled, boolean disableOtherSubscriptions)342 public static void setMobileDataEnabled(Context context, int subId, boolean enabled, 343 boolean disableOtherSubscriptions) { 344 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) 345 .createForSubscriptionId(subId); 346 final SubscriptionManager subscriptionManager = context.getSystemService( 347 SubscriptionManager.class); 348 telephonyManager.setDataEnabled(enabled); 349 350 if (disableOtherSubscriptions) { 351 final List<SubscriptionInfo> subInfoList = 352 subscriptionManager.getActiveSubscriptionInfoList(); 353 if (subInfoList != null) { 354 for (SubscriptionInfo subInfo : subInfoList) { 355 // We never disable mobile data for opportunistic subscriptions. 356 if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) { 357 context.getSystemService(TelephonyManager.class).createForSubscriptionId( 358 subInfo.getSubscriptionId()).setDataEnabled(false); 359 } 360 } 361 } 362 } 363 } 364 365 /** 366 * Return {@code true} if show CDMA category 367 */ isCdmaOptions(Context context, int subId)368 public static boolean isCdmaOptions(Context context, int subId) { 369 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 370 return false; 371 } 372 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) 373 .createForSubscriptionId(subId); 374 final PersistableBundle carrierConfig = context.getSystemService( 375 CarrierConfigManager.class).getConfigForSubId(subId); 376 377 378 if (telephonyManager.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) { 379 return true; 380 } else if (carrierConfig != null 381 && !carrierConfig.getBoolean( 382 CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) 383 && carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { 384 return true; 385 } 386 387 if (isWorldMode(context, subId)) { 388 final int settingsNetworkMode = android.provider.Settings.Global.getInt( 389 context.getContentResolver(), 390 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, 391 Phone.PREFERRED_NT_MODE); 392 if (settingsNetworkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA 393 || settingsNetworkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO) { 394 return true; 395 } 396 397 if (shouldSpeciallyUpdateGsmCdma(context, subId)) { 398 return true; 399 } 400 } 401 402 return false; 403 } 404 405 /** 406 * return {@code true} if we need show Gsm related settings 407 */ isGsmOptions(Context context, int subId)408 public static boolean isGsmOptions(Context context, int subId) { 409 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 410 return false; 411 } 412 if (isGsmBasicOptions(context, subId)) { 413 return true; 414 } 415 final int networkMode = android.provider.Settings.Global.getInt( 416 context.getContentResolver(), 417 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, 418 Phone.PREFERRED_NT_MODE); 419 if (isWorldMode(context, subId)) { 420 if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO 421 || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA) { 422 return true; 423 } else if (shouldSpeciallyUpdateGsmCdma(context, subId)) { 424 return true; 425 } 426 } 427 428 return false; 429 } 430 isGsmBasicOptions(Context context, int subId)431 private static boolean isGsmBasicOptions(Context context, int subId) { 432 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) 433 .createForSubscriptionId(subId); 434 final PersistableBundle carrierConfig = context.getSystemService( 435 CarrierConfigManager.class).getConfigForSubId(subId); 436 437 if (telephonyManager.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) { 438 return true; 439 } else if (carrierConfig != null 440 && !carrierConfig.getBoolean( 441 CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) 442 && carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { 443 return true; 444 } 445 446 return false; 447 } 448 449 /** 450 * Return {@code true} if it is world mode, and we may show advanced options in telephony 451 * settings 452 */ isWorldMode(Context context, int subId)453 public static boolean isWorldMode(Context context, int subId) { 454 final PersistableBundle carrierConfig = context.getSystemService( 455 CarrierConfigManager.class).getConfigForSubId(subId); 456 return carrierConfig == null 457 ? false 458 : carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL); 459 } 460 461 /** 462 * Return {@code true} if we need show settings for network selection(i.e. Verizon) 463 */ shouldDisplayNetworkSelectOptions(Context context, int subId)464 public static boolean shouldDisplayNetworkSelectOptions(Context context, int subId) { 465 final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) 466 .createForSubscriptionId(subId); 467 final PersistableBundle carrierConfig = context.getSystemService( 468 CarrierConfigManager.class).getConfigForSubId(subId); 469 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 470 || carrierConfig == null 471 || !carrierConfig.getBoolean( 472 CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL) 473 || carrierConfig.getBoolean( 474 CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) 475 || (carrierConfig.getBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL) 476 && !telephonyManager.isManualNetworkSelectionAllowed())) { 477 return false; 478 } 479 480 final int networkMode = android.provider.Settings.Global.getInt( 481 context.getContentResolver(), 482 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, 483 Phone.PREFERRED_NT_MODE); 484 if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO 485 && isWorldMode(context, subId)) { 486 return false; 487 } 488 if (shouldSpeciallyUpdateGsmCdma(context, subId)) { 489 return false; 490 } 491 492 if (isGsmBasicOptions(context, subId)) { 493 return true; 494 } 495 496 if (isWorldMode(context, subId)) { 497 if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA) { 498 return true; 499 } 500 } 501 502 return false; 503 } 504 505 /** 506 * Return {@code true} if Tdscdma is supported in current subscription 507 */ isTdscdmaSupported(Context context, int subId)508 public static boolean isTdscdmaSupported(Context context, int subId) { 509 return isTdscdmaSupported(context, 510 context.getSystemService(TelephonyManager.class).createForSubscriptionId(subId)); 511 } 512 513 //TODO(b/117651939): move it to telephony isTdscdmaSupported(Context context, TelephonyManager telephonyManager)514 private static boolean isTdscdmaSupported(Context context, TelephonyManager telephonyManager) { 515 final PersistableBundle carrierConfig = context.getSystemService( 516 CarrierConfigManager.class).getConfig(); 517 518 if (carrierConfig == null) { 519 return false; 520 } 521 522 if (carrierConfig.getBoolean(CarrierConfigManager.KEY_SUPPORT_TDSCDMA_BOOL)) { 523 return true; 524 } 525 526 final String operatorNumeric = telephonyManager.getServiceState().getOperatorNumeric(); 527 final String[] numericArray = carrierConfig.getStringArray( 528 CarrierConfigManager.KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY); 529 if (numericArray == null || operatorNumeric == null) { 530 return false; 531 } 532 for (String numeric : numericArray) { 533 if (operatorNumeric.equals(numeric)) { 534 return true; 535 } 536 } 537 return false; 538 } 539 540 /** 541 * Return subId that supported by search. If there are more than one, return first one, 542 * otherwise return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} 543 */ getSearchableSubscriptionId(Context context)544 public static int getSearchableSubscriptionId(Context context) { 545 final int[] subIds = getActiveSubscriptionIdList(context); 546 547 return subIds.length >= 1 ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID; 548 } 549 550 /** 551 * Return availability for a default subscription id. If subId already been set, use it to 552 * check, otherwise traverse all active subIds on device to check. 553 * @param context context 554 * @param defSubId Default subId get from telephony preference controller 555 * @param callback Callback to check availability for a specific subId 556 * @return Availability 557 * 558 * @see BasePreferenceController#getAvailabilityStatus() 559 */ getAvailability(Context context, int defSubId, TelephonyAvailabilityCallback callback)560 public static int getAvailability(Context context, int defSubId, 561 TelephonyAvailabilityCallback callback) { 562 if (defSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 563 // If subId has been set, return the corresponding status 564 return callback.getAvailabilityStatus(defSubId); 565 } else { 566 // Otherwise, search whether there is one subId in device that support this preference 567 final int[] subIds = getActiveSubscriptionIdList(context); 568 if (ArrayUtils.isEmpty(subIds)) { 569 return callback.getAvailabilityStatus( 570 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 571 } else { 572 for (final int subId : subIds) { 573 final int status = callback.getAvailabilityStatus(subId); 574 if (status == BasePreferenceController.AVAILABLE) { 575 return status; 576 } 577 } 578 return callback.getAvailabilityStatus(subIds[0]); 579 } 580 } 581 } 582 583 /** 584 * This method is migrated from {@link com.android.phone.MobileNetworkSettings} and we should 585 * use it carefully. This code snippet doesn't have very clear meaning however we should 586 * update GSM or CDMA differently based on what it returns. 587 * 588 * 1. For all CDMA settings, make them visible if it return {@code true} 589 * 2. For GSM settings, make them visible if it return {@code true} unless 3 590 * 3. For network select settings, make it invisible if it return {@code true} 591 */ 592 @VisibleForTesting shouldSpeciallyUpdateGsmCdma(Context context, int subId)593 static boolean shouldSpeciallyUpdateGsmCdma(Context context, int subId) { 594 final int networkMode = android.provider.Settings.Global.getInt( 595 context.getContentResolver(), 596 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, 597 Phone.PREFERRED_NT_MODE); 598 if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM 599 || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA 600 || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA 601 || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA 602 || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA 603 || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA) { 604 if (!isTdscdmaSupported(context, subId) && isWorldMode(context, subId)) { 605 return true; 606 } 607 } 608 609 return false; 610 } 611 getSignalStrengthIcon(Context context, int level, int numLevels, int iconType, boolean cutOut)612 public static Drawable getSignalStrengthIcon(Context context, int level, int numLevels, 613 int iconType, boolean cutOut) { 614 final SignalDrawable signalDrawable = new SignalDrawable(context); 615 signalDrawable.setLevel( 616 SignalDrawable.getState(level, numLevels, cutOut)); 617 618 // Make the network type drawable 619 final Drawable networkDrawable = 620 iconType == NO_CELL_DATA_TYPE_ICON 621 ? EMPTY_DRAWABLE 622 : context 623 .getResources().getDrawable(iconType, context.getTheme()); 624 625 // Overlay the two drawables 626 final Drawable[] layers = {networkDrawable, signalDrawable}; 627 final int iconSize = 628 context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size); 629 630 final LayerDrawable icons = new LayerDrawable(layers); 631 // Set the network type icon at the top left 632 icons.setLayerGravity(0 /* index of networkDrawable */, Gravity.TOP | Gravity.LEFT); 633 // Set the signal strength icon at the bottom right 634 icons.setLayerGravity(1 /* index of SignalDrawable */, Gravity.BOTTOM | Gravity.RIGHT); 635 icons.setLayerSize(1 /* index of SignalDrawable */, iconSize, iconSize); 636 icons.setTintList(Utils.getColorAttr(context, android.R.attr.colorControlNormal)); 637 return icons; 638 } 639 640 /** 641 * This method is migrated from 642 * {@link android.telephony.TelephonyManager.getNetworkOperatorName}. Which provides 643 * 644 * 1. Better support under multi-SIM environment. 645 * 2. Similar design which aligned with operator name displayed in status bar 646 */ getCurrentCarrierNameForDisplay(Context context, int subId)647 public static CharSequence getCurrentCarrierNameForDisplay(Context context, int subId) { 648 final SubscriptionManager sm = context.getSystemService(SubscriptionManager.class); 649 if (sm != null) { 650 final SubscriptionInfo subInfo = getSubscriptionInfo(sm, subId); 651 if (subInfo != null) { 652 return subInfo.getCarrierName(); 653 } 654 } 655 return getOperatorNameFromTelephonyManager(context); 656 } 657 getCurrentCarrierNameForDisplay(Context context)658 public static CharSequence getCurrentCarrierNameForDisplay(Context context) { 659 final SubscriptionManager sm = context.getSystemService(SubscriptionManager.class); 660 if (sm != null) { 661 final int subId = sm.getDefaultSubscriptionId(); 662 final SubscriptionInfo subInfo = getSubscriptionInfo(sm, subId); 663 if (subInfo != null) { 664 return subInfo.getCarrierName(); 665 } 666 } 667 return getOperatorNameFromTelephonyManager(context); 668 } 669 getSubscriptionInfo(SubscriptionManager subManager, int subId)670 private static SubscriptionInfo getSubscriptionInfo(SubscriptionManager subManager, 671 int subId) { 672 List<SubscriptionInfo> subInfos = subManager.getAccessibleSubscriptionInfoList(); 673 if (subInfos == null) { 674 subInfos = subManager.getActiveSubscriptionInfoList(); 675 } 676 if (subInfos == null) { 677 return null; 678 } 679 for (SubscriptionInfo subInfo : subInfos) { 680 if (subInfo.getSubscriptionId() == subId) { 681 return subInfo; 682 } 683 } 684 return null; 685 } 686 getOperatorNameFromTelephonyManager(Context context)687 private static String getOperatorNameFromTelephonyManager(Context context) { 688 final TelephonyManager tm = 689 (TelephonyManager) context.getSystemService(TelephonyManager.class); 690 if (tm == null) { 691 return null; 692 } 693 return tm.getNetworkOperatorName(); 694 } 695 isEsimSupportedCountry(String country, String countriesListString)696 private static boolean isEsimSupportedCountry(String country, String countriesListString) { 697 if (TextUtils.isEmpty(country)) { 698 return true; 699 } else if (TextUtils.isEmpty(countriesListString)) { 700 return false; 701 } 702 final List<String> supportedCountries = 703 Arrays.asList(TextUtils.split(countriesListString.toLowerCase(), ",")); 704 return supportedCountries.contains(country); 705 } 706 isEsimUnsupportedCountry(String country, String countriesListString)707 private static boolean isEsimUnsupportedCountry(String country, String countriesListString) { 708 if (TextUtils.isEmpty(country) || TextUtils.isEmpty(countriesListString)) { 709 return false; 710 } 711 final List<String> unsupportedCountries = 712 Arrays.asList(TextUtils.split(countriesListString.toLowerCase(), ",")); 713 return unsupportedCountries.contains(country); 714 } 715 getActiveSubscriptionIdList(Context context)716 private static int[] getActiveSubscriptionIdList(Context context) { 717 final SubscriptionManager subscriptionManager = context.getSystemService( 718 SubscriptionManager.class); 719 final List<SubscriptionInfo> subInfoList = 720 subscriptionManager.getActiveSubscriptionInfoList(); 721 if (subInfoList == null) { 722 return new int[0]; 723 } 724 int[] activeSubIds = new int[subInfoList.size()]; 725 int i = 0; 726 for (SubscriptionInfo subInfo : subInfoList) { 727 activeSubIds[i] = subInfo.getSubscriptionId(); 728 i++; 729 } 730 return activeSubIds; 731 } 732 } 733