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