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