| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.settings.network.telephony; |
| |
| import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI; |
| |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ResolveInfo; |
| import android.database.Cursor; |
| import android.graphics.Color; |
| import android.graphics.drawable.ColorDrawable; |
| import android.graphics.drawable.Drawable; |
| import android.graphics.drawable.LayerDrawable; |
| import android.os.PersistableBundle; |
| import android.os.SystemClock; |
| import android.os.SystemProperties; |
| import android.provider.Settings; |
| import android.telecom.PhoneAccountHandle; |
| import android.telecom.TelecomManager; |
| import android.telephony.CarrierConfigManager; |
| import android.telephony.SubscriptionInfo; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| import android.telephony.euicc.EuiccManager; |
| import android.telephony.ims.ImsRcsManager; |
| import android.telephony.ims.ProvisioningManager; |
| import android.telephony.ims.RcsUceAdapter; |
| import android.telephony.ims.feature.ImsFeature; |
| import android.telephony.ims.feature.MmTelFeature; |
| import android.telephony.ims.stub.ImsRegistrationImplBase; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.view.Gravity; |
| |
| import androidx.annotation.VisibleForTesting; |
| |
| import com.android.ims.ImsException; |
| import com.android.ims.ImsManager; |
| import com.android.internal.telephony.Phone; |
| import com.android.internal.util.ArrayUtils; |
| import com.android.settings.R; |
| import com.android.settings.Utils; |
| import com.android.settings.core.BasePreferenceController; |
| import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants; |
| import com.android.settingslib.development.DevelopmentSettingsEnabler; |
| import com.android.settingslib.graph.SignalDrawable; |
| import com.android.settingslib.utils.ThreadUtils; |
| |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.Future; |
| |
| public class MobileNetworkUtils { |
| |
| private static final String TAG = "MobileNetworkUtils"; |
| |
| // CID of the device. |
| private static final String KEY_CID = "ro.boot.cid"; |
| // CIDs of devices which should not show anything related to eSIM. |
| private static final String KEY_ESIM_CID_IGNORE = "ro.setupwizard.esim_cid_ignore"; |
| // System Property which is used to decide whether the default eSIM UI will be shown, |
| // the default value is false. |
| private static final String KEY_ENABLE_ESIM_UI_BY_DEFAULT = |
| "esim.enable_esim_system_ui_by_default"; |
| private static final String LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT = |
| "android.telecom.action.CONNECTION_SERVICE_CONFIGURE"; |
| |
| // The following constants are used to draw signal icon. |
| public static final int NO_CELL_DATA_TYPE_ICON = 0; |
| public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT); |
| |
| /** |
| * Returns if DPC APNs are enforced. |
| */ |
| public static boolean isDpcApnEnforced(Context context) { |
| try (Cursor enforceCursor = context.getContentResolver().query(ENFORCE_MANAGED_URI, |
| null, null, null, null)) { |
| if (enforceCursor == null || enforceCursor.getCount() != 1) { |
| return false; |
| } |
| enforceCursor.moveToFirst(); |
| return enforceCursor.getInt(0) > 0; |
| } |
| } |
| |
| /** |
| * Returns true if Wifi calling is enabled for at least one subscription. |
| */ |
| public static boolean isWifiCallingEnabled(Context context) { |
| final int[] subIds = getActiveSubscriptionIdList(context); |
| if (ArrayUtils.isEmpty(subIds)) { |
| Log.d(TAG, "isWifiCallingEnabled: subIds is empty"); |
| return false; |
| } |
| for (int subId : subIds) { |
| if (isWifiCallingEnabled(context, subId)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns true if Wifi calling is provisioned for the specific subscription with id |
| * {@code subId}. |
| */ |
| @VisibleForTesting |
| public static boolean isWfcProvisionedOnDevice(int subId) { |
| final ProvisioningManager provisioningMgr = |
| ProvisioningManager.createForSubscriptionId(subId); |
| if (provisioningMgr == null) { |
| return true; |
| } |
| return provisioningMgr.getProvisioningStatusForCapability( |
| MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, |
| ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); |
| } |
| |
| /** |
| * Returns true if Wifi calling is enabled for the specific subscription with id {@code subId}. |
| */ |
| public static boolean isWifiCallingEnabled(Context context, int subId) { |
| final PhoneAccountHandle simCallManager = |
| context.getSystemService(TelecomManager.class) |
| .getSimCallManagerForSubscription(subId); |
| final int phoneId = SubscriptionManager.getSlotIndex(subId); |
| |
| boolean isWifiCallingEnabled; |
| if (simCallManager != null) { |
| final Intent intent = buildPhoneAccountConfigureIntent( |
| context, simCallManager); |
| |
| isWifiCallingEnabled = intent != null; |
| } else { |
| final ImsManager imsMgr = ImsManager.getInstance(context, phoneId); |
| isWifiCallingEnabled = imsMgr != null |
| && imsMgr.isWfcEnabledByPlatform() |
| && isWfcProvisionedOnDevice(subId) |
| && isImsServiceStateReady(imsMgr); |
| } |
| |
| return isWifiCallingEnabled; |
| } |
| |
| /** |
| * @return The current user setting for whether or not contact discovery is enabled for the |
| * subscription id specified. |
| * @see RcsUceAdapter#isUceSettingEnabled() |
| */ |
| public static boolean isContactDiscoveryEnabled(Context context, int subId) { |
| android.telephony.ims.ImsManager imsManager = |
| context.getSystemService(android.telephony.ims.ImsManager.class); |
| return isContactDiscoveryEnabled(imsManager, subId); |
| } |
| |
| /** |
| * @return The current user setting for whether or not contact discovery is enabled for the |
| * subscription id specified. |
| * @see RcsUceAdapter#isUceSettingEnabled() |
| */ |
| public static boolean isContactDiscoveryEnabled(android.telephony.ims.ImsManager imsManager, |
| int subId) { |
| ImsRcsManager manager = getImsRcsManager(imsManager, subId); |
| if (manager == null) return false; |
| RcsUceAdapter adapter = manager.getUceAdapter(); |
| try { |
| return adapter.isUceSettingEnabled(); |
| } catch (android.telephony.ims.ImsException e) { |
| Log.w(TAG, "UCE service is not available: " + e.getMessage()); |
| } |
| return false; |
| } |
| |
| /** |
| * Set the new user setting to enable or disable contact discovery through RCS UCE. |
| * @see RcsUceAdapter#setUceSettingEnabled(boolean) |
| */ |
| public static void setContactDiscoveryEnabled(android.telephony.ims.ImsManager imsManager, |
| int subId, boolean isEnabled) { |
| ImsRcsManager manager = getImsRcsManager(imsManager, subId); |
| if (manager == null) return; |
| RcsUceAdapter adapter = manager.getUceAdapter(); |
| try { |
| adapter.setUceSettingEnabled(isEnabled); |
| } catch (android.telephony.ims.ImsException e) { |
| Log.w(TAG, "UCE service is not available: " + e.getMessage()); |
| } |
| } |
| |
| /** |
| * @return The ImsRcsManager associated with the subscription specified. |
| */ |
| private static ImsRcsManager getImsRcsManager(android.telephony.ims.ImsManager imsManager, |
| int subId) { |
| if (imsManager == null) return null; |
| try { |
| return imsManager.getImsRcsManager(subId); |
| } catch (Exception e) { |
| Log.w(TAG, "Could not resolve ImsRcsManager: " + e.getMessage()); |
| } |
| return null; |
| } |
| |
| /** |
| * @return true if contact discovery is available for the subscription specified and the option |
| * should be shown to the user, false if the option should be hidden. |
| */ |
| public static boolean isContactDiscoveryVisible(Context context, int subId) { |
| CarrierConfigManager carrierConfigManager = context.getSystemService( |
| CarrierConfigManager.class); |
| if (carrierConfigManager == null) { |
| Log.w(TAG, "isContactDiscoveryVisible: Could not resolve carrier config"); |
| return false; |
| } |
| PersistableBundle bundle = carrierConfigManager.getConfigForSubId(subId); |
| return bundle.getBoolean(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, false /*default*/); |
| } |
| |
| @VisibleForTesting |
| static Intent buildPhoneAccountConfigureIntent( |
| Context context, PhoneAccountHandle accountHandle) { |
| Intent intent = buildConfigureIntent( |
| context, accountHandle, TelecomManager.ACTION_CONFIGURE_PHONE_ACCOUNT); |
| |
| if (intent == null) { |
| // If the new configuration didn't work, try the old configuration intent. |
| intent = buildConfigureIntent(context, accountHandle, |
| LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT); |
| } |
| return intent; |
| } |
| |
| private static Intent buildConfigureIntent( |
| Context context, PhoneAccountHandle accountHandle, String actionStr) { |
| if (accountHandle == null || accountHandle.getComponentName() == null |
| || TextUtils.isEmpty(accountHandle.getComponentName().getPackageName())) { |
| return null; |
| } |
| |
| // Build the settings intent. |
| Intent intent = new Intent(actionStr); |
| intent.setPackage(accountHandle.getComponentName().getPackageName()); |
| intent.addCategory(Intent.CATEGORY_DEFAULT); |
| intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); |
| |
| // Check to see that the phone account package can handle the setting intent. |
| final PackageManager pm = context.getPackageManager(); |
| final List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0); |
| if (resolutions.size() == 0) { |
| intent = null; // set no intent if the package cannot handle it. |
| } |
| |
| return intent; |
| } |
| |
| public static boolean isImsServiceStateReady(ImsManager imsMgr) { |
| boolean isImsServiceStateReady = false; |
| |
| try { |
| if (imsMgr != null && imsMgr.getImsServiceState() == ImsFeature.STATE_READY) { |
| isImsServiceStateReady = true; |
| } |
| } catch (ImsException ex) { |
| Log.e(TAG, "Exception when trying to get ImsServiceStatus: " + ex); |
| } |
| |
| Log.d(TAG, "isImsServiceStateReady=" + isImsServiceStateReady); |
| return isImsServiceStateReady; |
| } |
| |
| /** |
| * Whether to show the entry point to eUICC settings. |
| * |
| * <p>We show the entry point on any device which supports eUICC as long as either the eUICC |
| * was ever provisioned (that is, at least one profile was ever downloaded onto it), or if |
| * the user has enabled development mode. |
| */ |
| public static boolean showEuiccSettings(Context context) { |
| long timeForAccess = SystemClock.elapsedRealtime(); |
| try { |
| return ((Future<Boolean>) ThreadUtils.postOnBackgroundThread(() |
| -> showEuiccSettingsDetecting(context))).get(); |
| } catch (ExecutionException | InterruptedException exception) { |
| timeForAccess = SystemClock.elapsedRealtime() - timeForAccess; |
| Log.w(TAG, "Accessing Euicc takes too long: +" + timeForAccess + "ms"); |
| } |
| return false; |
| } |
| |
| private static Boolean showEuiccSettingsDetecting(Context context) { |
| final EuiccManager euiccManager = |
| (EuiccManager) context.getSystemService(EuiccManager.class); |
| if (!euiccManager.isEnabled()) { |
| return false; |
| } |
| |
| final ContentResolver cr = context.getContentResolver(); |
| |
| final TelephonyManager tm = |
| (TelephonyManager) context.getSystemService(TelephonyManager.class); |
| final String currentCountry = tm.getNetworkCountryIso().toLowerCase(); |
| final String supportedCountries = |
| Settings.Global.getString(cr, Settings.Global.EUICC_SUPPORTED_COUNTRIES); |
| final String unsupportedCountries = |
| Settings.Global.getString(cr, Settings.Global.EUICC_UNSUPPORTED_COUNTRIES); |
| |
| boolean inEsimSupportedCountries = false; |
| |
| if (TextUtils.isEmpty(supportedCountries)) { |
| // White list is empty, use blacklist. |
| Log.d(TAG, "Using blacklist unsupportedCountries=" + unsupportedCountries); |
| inEsimSupportedCountries = !isEsimUnsupportedCountry(currentCountry, |
| unsupportedCountries); |
| } else { |
| Log.d(TAG, "Using whitelist supportedCountries=" + supportedCountries); |
| inEsimSupportedCountries = isEsimSupportedCountry(currentCountry, supportedCountries); |
| } |
| |
| Log.d(TAG, "inEsimSupportedCountries=" + inEsimSupportedCountries); |
| |
| final boolean esimIgnoredDevice = |
| Arrays.asList(TextUtils.split(SystemProperties.get(KEY_ESIM_CID_IGNORE, ""), ",")) |
| .contains(SystemProperties.get(KEY_CID, null)); |
| final boolean enabledEsimUiByDefault = |
| SystemProperties.getBoolean(KEY_ENABLE_ESIM_UI_BY_DEFAULT, true); |
| final boolean euiccProvisioned = |
| Settings.Global.getInt(cr, Settings.Global.EUICC_PROVISIONED, 0) != 0; |
| final boolean inDeveloperMode = |
| DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context); |
| |
| return (inDeveloperMode || euiccProvisioned |
| || (!esimIgnoredDevice && enabledEsimUiByDefault && inEsimSupportedCountries)); |
| } |
| |
| /** |
| * Set whether to enable data for {@code subId}, also whether to disable data for other |
| * subscription |
| */ |
| public static void setMobileDataEnabled(Context context, int subId, boolean enabled, |
| boolean disableOtherSubscriptions) { |
| final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) |
| .createForSubscriptionId(subId); |
| final SubscriptionManager subscriptionManager = context.getSystemService( |
| SubscriptionManager.class); |
| telephonyManager.setDataEnabled(enabled); |
| |
| if (disableOtherSubscriptions) { |
| final List<SubscriptionInfo> subInfoList = |
| subscriptionManager.getActiveSubscriptionInfoList(); |
| if (subInfoList != null) { |
| for (SubscriptionInfo subInfo : subInfoList) { |
| // We never disable mobile data for opportunistic subscriptions. |
| if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) { |
| context.getSystemService(TelephonyManager.class).createForSubscriptionId( |
| subInfo.getSubscriptionId()).setDataEnabled(false); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Return {@code true} if show CDMA category |
| */ |
| public static boolean isCdmaOptions(Context context, int subId) { |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return false; |
| } |
| final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) |
| .createForSubscriptionId(subId); |
| final PersistableBundle carrierConfig = context.getSystemService( |
| CarrierConfigManager.class).getConfigForSubId(subId); |
| |
| |
| if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { |
| return true; |
| } else if (carrierConfig != null |
| && !carrierConfig.getBoolean( |
| CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) |
| && carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { |
| return true; |
| } |
| |
| if (isWorldMode(context, subId)) { |
| final int settingsNetworkMode = android.provider.Settings.Global.getInt( |
| context.getContentResolver(), |
| android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, |
| Phone.PREFERRED_NT_MODE); |
| if (settingsNetworkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA |
| || settingsNetworkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO) { |
| return true; |
| } |
| |
| if (shouldSpeciallyUpdateGsmCdma(context, subId)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * return {@code true} if we need show Gsm related settings |
| */ |
| public static boolean isGsmOptions(Context context, int subId) { |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return false; |
| } |
| if (isGsmBasicOptions(context, subId)) { |
| return true; |
| } |
| final int networkMode = android.provider.Settings.Global.getInt( |
| context.getContentResolver(), |
| android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, |
| Phone.PREFERRED_NT_MODE); |
| if (isWorldMode(context, subId)) { |
| if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO |
| || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA) { |
| return true; |
| } else if (shouldSpeciallyUpdateGsmCdma(context, subId)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| private static boolean isGsmBasicOptions(Context context, int subId) { |
| final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) |
| .createForSubscriptionId(subId); |
| final PersistableBundle carrierConfig = context.getSystemService( |
| CarrierConfigManager.class).getConfigForSubId(subId); |
| |
| if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) { |
| return true; |
| } else if (carrierConfig != null |
| && !carrierConfig.getBoolean( |
| CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) |
| && carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Return {@code true} if it is world mode, and we may show advanced options in telephony |
| * settings |
| */ |
| public static boolean isWorldMode(Context context, int subId) { |
| final PersistableBundle carrierConfig = context.getSystemService( |
| CarrierConfigManager.class).getConfigForSubId(subId); |
| return carrierConfig == null |
| ? false |
| : carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL); |
| } |
| |
| /** |
| * Return {@code true} if we need show settings for network selection(i.e. Verizon) |
| */ |
| public static boolean shouldDisplayNetworkSelectOptions(Context context, int subId) { |
| final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) |
| .createForSubscriptionId(subId); |
| final PersistableBundle carrierConfig = context.getSystemService( |
| CarrierConfigManager.class).getConfigForSubId(subId); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID |
| || carrierConfig == null |
| || !carrierConfig.getBoolean( |
| CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL) |
| || carrierConfig.getBoolean( |
| CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) |
| || (carrierConfig.getBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL) |
| && !telephonyManager.isManualNetworkSelectionAllowed())) { |
| return false; |
| } |
| |
| final int networkMode = android.provider.Settings.Global.getInt( |
| context.getContentResolver(), |
| android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, |
| Phone.PREFERRED_NT_MODE); |
| if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO |
| && isWorldMode(context, subId)) { |
| return false; |
| } |
| if (shouldSpeciallyUpdateGsmCdma(context, subId)) { |
| return false; |
| } |
| |
| if (isGsmBasicOptions(context, subId)) { |
| return true; |
| } |
| |
| if (isWorldMode(context, subId)) { |
| if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Return {@code true} if Tdscdma is supported in current subscription |
| */ |
| public static boolean isTdscdmaSupported(Context context, int subId) { |
| return isTdscdmaSupported(context, |
| context.getSystemService(TelephonyManager.class).createForSubscriptionId(subId)); |
| } |
| |
| //TODO(b/117651939): move it to telephony |
| private static boolean isTdscdmaSupported(Context context, TelephonyManager telephonyManager) { |
| final PersistableBundle carrierConfig = context.getSystemService( |
| CarrierConfigManager.class).getConfig(); |
| |
| if (carrierConfig == null) { |
| return false; |
| } |
| |
| if (carrierConfig.getBoolean(CarrierConfigManager.KEY_SUPPORT_TDSCDMA_BOOL)) { |
| return true; |
| } |
| |
| final String operatorNumeric = telephonyManager.getServiceState().getOperatorNumeric(); |
| final String[] numericArray = carrierConfig.getStringArray( |
| CarrierConfigManager.KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY); |
| if (numericArray == null || operatorNumeric == null) { |
| return false; |
| } |
| for (String numeric : numericArray) { |
| if (operatorNumeric.equals(numeric)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Return subId that supported by search. If there are more than one, return first one, |
| * otherwise return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} |
| */ |
| public static int getSearchableSubscriptionId(Context context) { |
| final int[] subIds = getActiveSubscriptionIdList(context); |
| |
| return subIds.length >= 1 ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| } |
| |
| /** |
| * Return availability for a default subscription id. If subId already been set, use it to |
| * check, otherwise traverse all active subIds on device to check. |
| * @param context context |
| * @param defSubId Default subId get from telephony preference controller |
| * @param callback Callback to check availability for a specific subId |
| * @return Availability |
| * |
| * @see BasePreferenceController#getAvailabilityStatus() |
| */ |
| public static int getAvailability(Context context, int defSubId, |
| TelephonyAvailabilityCallback callback) { |
| if (defSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| // If subId has been set, return the corresponding status |
| return callback.getAvailabilityStatus(defSubId); |
| } else { |
| // Otherwise, search whether there is one subId in device that support this preference |
| final int[] subIds = getActiveSubscriptionIdList(context); |
| if (ArrayUtils.isEmpty(subIds)) { |
| return callback.getAvailabilityStatus( |
| SubscriptionManager.INVALID_SUBSCRIPTION_ID); |
| } else { |
| for (final int subId : subIds) { |
| final int status = callback.getAvailabilityStatus(subId); |
| if (status == BasePreferenceController.AVAILABLE) { |
| return status; |
| } |
| } |
| return callback.getAvailabilityStatus(subIds[0]); |
| } |
| } |
| } |
| |
| /** |
| * This method is migrated from {@link com.android.phone.MobileNetworkSettings} and we should |
| * use it carefully. This code snippet doesn't have very clear meaning however we should |
| * update GSM or CDMA differently based on what it returns. |
| * |
| * 1. For all CDMA settings, make them visible if it return {@code true} |
| * 2. For GSM settings, make them visible if it return {@code true} unless 3 |
| * 3. For network select settings, make it invisible if it return {@code true} |
| */ |
| @VisibleForTesting |
| static boolean shouldSpeciallyUpdateGsmCdma(Context context, int subId) { |
| final int networkMode = android.provider.Settings.Global.getInt( |
| context.getContentResolver(), |
| android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, |
| Phone.PREFERRED_NT_MODE); |
| if (networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM |
| || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA |
| || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA |
| || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA |
| || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA |
| || networkMode == TelephonyManagerConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA) { |
| if (!isTdscdmaSupported(context, subId) && isWorldMode(context, subId)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| public static Drawable getSignalStrengthIcon(Context context, int level, int numLevels, |
| int iconType, boolean cutOut) { |
| final SignalDrawable signalDrawable = new SignalDrawable(context); |
| signalDrawable.setLevel( |
| SignalDrawable.getState(level, numLevels, cutOut)); |
| |
| // Make the network type drawable |
| final Drawable networkDrawable = |
| iconType == NO_CELL_DATA_TYPE_ICON |
| ? EMPTY_DRAWABLE |
| : context |
| .getResources().getDrawable(iconType, context.getTheme()); |
| |
| // Overlay the two drawables |
| final Drawable[] layers = {networkDrawable, signalDrawable}; |
| final int iconSize = |
| context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size); |
| |
| final LayerDrawable icons = new LayerDrawable(layers); |
| // Set the network type icon at the top left |
| icons.setLayerGravity(0 /* index of networkDrawable */, Gravity.TOP | Gravity.LEFT); |
| // Set the signal strength icon at the bottom right |
| icons.setLayerGravity(1 /* index of SignalDrawable */, Gravity.BOTTOM | Gravity.RIGHT); |
| icons.setLayerSize(1 /* index of SignalDrawable */, iconSize, iconSize); |
| icons.setTintList(Utils.getColorAttr(context, android.R.attr.colorControlNormal)); |
| return icons; |
| } |
| |
| /** |
| * This method is migrated from |
| * {@link android.telephony.TelephonyManager.getNetworkOperatorName}. Which provides |
| * |
| * 1. Better support under multi-SIM environment. |
| * 2. Similar design which aligned with operator name displayed in status bar |
| */ |
| public static CharSequence getCurrentCarrierNameForDisplay(Context context, int subId) { |
| final SubscriptionManager sm = context.getSystemService(SubscriptionManager.class); |
| if (sm != null) { |
| final SubscriptionInfo subInfo = getSubscriptionInfo(sm, subId); |
| if (subInfo != null) { |
| return subInfo.getCarrierName(); |
| } |
| } |
| return getOperatorNameFromTelephonyManager(context); |
| } |
| |
| public static CharSequence getCurrentCarrierNameForDisplay(Context context) { |
| final SubscriptionManager sm = context.getSystemService(SubscriptionManager.class); |
| if (sm != null) { |
| final int subId = sm.getDefaultSubscriptionId(); |
| final SubscriptionInfo subInfo = getSubscriptionInfo(sm, subId); |
| if (subInfo != null) { |
| return subInfo.getCarrierName(); |
| } |
| } |
| return getOperatorNameFromTelephonyManager(context); |
| } |
| |
| private static SubscriptionInfo getSubscriptionInfo(SubscriptionManager subManager, |
| int subId) { |
| List<SubscriptionInfo> subInfos = subManager.getAccessibleSubscriptionInfoList(); |
| if (subInfos == null) { |
| subInfos = subManager.getActiveSubscriptionInfoList(); |
| } |
| if (subInfos == null) { |
| return null; |
| } |
| for (SubscriptionInfo subInfo : subInfos) { |
| if (subInfo.getSubscriptionId() == subId) { |
| return subInfo; |
| } |
| } |
| return null; |
| } |
| |
| private static String getOperatorNameFromTelephonyManager(Context context) { |
| final TelephonyManager tm = |
| (TelephonyManager) context.getSystemService(TelephonyManager.class); |
| if (tm == null) { |
| return null; |
| } |
| return tm.getNetworkOperatorName(); |
| } |
| |
| private static boolean isEsimSupportedCountry(String country, String countriesListString) { |
| if (TextUtils.isEmpty(country)) { |
| return true; |
| } else if (TextUtils.isEmpty(countriesListString)) { |
| return false; |
| } |
| final List<String> supportedCountries = |
| Arrays.asList(TextUtils.split(countriesListString.toLowerCase(), ",")); |
| return supportedCountries.contains(country); |
| } |
| |
| private static boolean isEsimUnsupportedCountry(String country, String countriesListString) { |
| if (TextUtils.isEmpty(country) || TextUtils.isEmpty(countriesListString)) { |
| return false; |
| } |
| final List<String> unsupportedCountries = |
| Arrays.asList(TextUtils.split(countriesListString.toLowerCase(), ",")); |
| return unsupportedCountries.contains(country); |
| } |
| |
| private static int[] getActiveSubscriptionIdList(Context context) { |
| final SubscriptionManager subscriptionManager = context.getSystemService( |
| SubscriptionManager.class); |
| final List<SubscriptionInfo> subInfoList = |
| subscriptionManager.getActiveSubscriptionInfoList(); |
| if (subInfoList == null) { |
| return new int[0]; |
| } |
| int[] activeSubIds = new int[subInfoList.size()]; |
| int i = 0; |
| for (SubscriptionInfo subInfo : subInfoList) { |
| activeSubIds[i] = subInfo.getSubscriptionId(); |
| i++; |
| } |
| return activeSubIds; |
| } |
| } |