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