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