1 /*
2  * Copyright (C) 2017 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.deviceinfo.simstatus;
18 
19 import static androidx.lifecycle.Lifecycle.Event;
20 
21 import android.annotation.Nullable;
22 import android.content.BroadcastReceiver;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.ServiceConnection;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ResolveInfo;
30 import android.content.res.Resources;
31 import android.os.IBinder;
32 import android.os.PersistableBundle;
33 import android.os.RemoteException;
34 import android.telephony.AccessNetworkConstants;
35 import android.telephony.Annotation;
36 import android.telephony.CarrierConfigManager;
37 import android.telephony.CellBroadcastIntents;
38 import android.telephony.CellBroadcastService;
39 import android.telephony.CellSignalStrength;
40 import android.telephony.ICellBroadcastService;
41 import android.telephony.ServiceState;
42 import android.telephony.SignalStrength;
43 import android.telephony.SubscriptionInfo;
44 import android.telephony.SubscriptionManager;
45 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
46 import android.telephony.TelephonyCallback;
47 import android.telephony.TelephonyDisplayInfo;
48 import android.telephony.TelephonyManager;
49 import android.telephony.UiccCardInfo;
50 import android.telephony.euicc.EuiccManager;
51 import android.telephony.ims.ImsException;
52 import android.telephony.ims.ImsMmTelManager;
53 import android.telephony.ims.ImsReasonInfo;
54 import android.text.TextUtils;
55 import android.util.Log;
56 
57 import androidx.annotation.NonNull;
58 import androidx.annotation.VisibleForTesting;
59 import androidx.lifecycle.LifecycleObserver;
60 import androidx.lifecycle.OnLifecycleEvent;
61 
62 import com.android.settings.R;
63 import com.android.settingslib.DeviceInfoUtils;
64 import com.android.settingslib.Utils;
65 import com.android.settingslib.core.lifecycle.Lifecycle;
66 import com.android.settingslib.utils.ThreadUtils;
67 
68 import java.util.List;
69 import java.util.Map;
70 import java.util.concurrent.atomic.AtomicReference;
71 
72 /**
73  * Controller for Sim Status information within the About Phone Settings page.
74  */
75 public class SimStatusDialogController implements LifecycleObserver {
76 
77     private final static String TAG = "SimStatusDialogCtrl";
78 
79     @VisibleForTesting
80     final static int NETWORK_PROVIDER_VALUE_ID = R.id.operator_name_value;
81     @VisibleForTesting
82     final static int PHONE_NUMBER_VALUE_ID = R.id.number_value;
83     @VisibleForTesting
84     final static int CELLULAR_NETWORK_STATE = R.id.data_state_value;
85     @VisibleForTesting
86     final static int OPERATOR_INFO_LABEL_ID = R.id.latest_area_info_label;
87     @VisibleForTesting
88     final static int OPERATOR_INFO_VALUE_ID = R.id.latest_area_info_value;
89     @VisibleForTesting
90     final static int SERVICE_STATE_VALUE_ID = R.id.service_state_value;
91     @VisibleForTesting
92     final static int SIGNAL_STRENGTH_LABEL_ID = R.id.signal_strength_label;
93     @VisibleForTesting
94     final static int SIGNAL_STRENGTH_VALUE_ID = R.id.signal_strength_value;
95     @VisibleForTesting
96     final static int CELL_VOICE_NETWORK_TYPE_VALUE_ID = R.id.voice_network_type_value;
97     @VisibleForTesting
98     final static int CELL_DATA_NETWORK_TYPE_VALUE_ID = R.id.data_network_type_value;
99     @VisibleForTesting
100     final static int ROAMING_INFO_VALUE_ID = R.id.roaming_state_value;
101     @VisibleForTesting
102     final static int ICCID_INFO_LABEL_ID = R.id.icc_id_label;
103     @VisibleForTesting
104     final static int ICCID_INFO_VALUE_ID = R.id.icc_id_value;
105     @VisibleForTesting
106     final static int EID_INFO_LABEL_ID = R.id.esim_id_label;
107     @VisibleForTesting
108     final static int EID_INFO_VALUE_ID = R.id.esim_id_value;
109     @VisibleForTesting
110     final static int IMS_REGISTRATION_STATE_LABEL_ID = R.id.ims_reg_state_label;
111     @VisibleForTesting
112     final static int IMS_REGISTRATION_STATE_VALUE_ID = R.id.ims_reg_state_value;
113 
114     @VisibleForTesting
115     static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
116 
117     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
118             new OnSubscriptionsChangedListener() {
119                 @Override
120                 public void onSubscriptionsChanged() {
121                     final int prevSubId = (mSubscriptionInfo != null)
122                             ? mSubscriptionInfo.getSubscriptionId()
123                             : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
124 
125                     mSubscriptionInfo = getPhoneSubscriptionInfo(mSlotIndex);
126 
127                     final int nextSubId = (mSubscriptionInfo != null)
128                             ? mSubscriptionInfo.getSubscriptionId()
129                             : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
130 
131                     if (prevSubId != nextSubId) {
132                         if (SubscriptionManager.isValidSubscriptionId(prevSubId)) {
133                             unregisterImsRegistrationCallback(prevSubId);
134                         }
135                         if (SubscriptionManager.isValidSubscriptionId(nextSubId)) {
136                             mTelephonyManager =
137                                     getTelephonyManager().createForSubscriptionId(nextSubId);
138                             registerImsRegistrationCallback(nextSubId);
139                         }
140                     }
141                     updateSubscriptionStatus();
142                 }
143             };
144 
145     private SubscriptionInfo mSubscriptionInfo;
146     private TelephonyDisplayInfo mTelephonyDisplayInfo;
147     private ServiceState mPreviousServiceState;
148 
149     private final int mSlotIndex;
150     private TelephonyManager mTelephonyManager;
151 
152     private final SimStatusDialogFragment mDialog;
153     private final SubscriptionManager mSubscriptionManager;
154     private final CarrierConfigManager mCarrierConfigManager;
155     private final EuiccManager mEuiccManager;
156     private final Resources mRes;
157     private final Context mContext;
158 
159     private boolean mShowLatestAreaInfo;
160     private boolean mIsRegisteredListener = false;
161 
162     private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() {
163         @Override
164         public void onReceive(Context context, Intent intent) {
165             if (CellBroadcastIntents.ACTION_AREA_INFO_UPDATED.equals(intent.getAction())
166                     && intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0)
167                     == mSlotIndex) {
168                 updateAreaInfoText();
169             }
170         }
171     };
172 
173     @VisibleForTesting
174     protected SimStatusDialogTelephonyCallback mTelephonyCallback;
175 
176     private CellBroadcastServiceConnection mCellBroadcastServiceConnection;
177 
178     private class CellBroadcastServiceConnection implements ServiceConnection {
179         private IBinder mService;
180 
181         @Nullable
getService()182         public IBinder getService() {
183             return mService;
184         }
185 
186         @Override
onServiceConnected(ComponentName className, IBinder service)187         public void onServiceConnected(ComponentName className, IBinder service) {
188             Log.d(TAG, "connected to CellBroadcastService");
189             this.mService = service;
190             updateAreaInfoText();
191         }
192 
193         @Override
onServiceDisconnected(ComponentName className)194         public void onServiceDisconnected(ComponentName className) {
195             this.mService = null;
196             Log.d(TAG, "mICellBroadcastService has disconnected unexpectedly");
197         }
198 
199         @Override
onBindingDied(ComponentName name)200         public void onBindingDied(ComponentName name) {
201             this.mService = null;
202             Log.d(TAG, "Binding died");
203         }
204 
205         @Override
onNullBinding(ComponentName name)206         public void onNullBinding(ComponentName name) {
207             this.mService = null;
208             Log.d(TAG, "Null binding");
209         }
210     }
211 
SimStatusDialogController(@onNull SimStatusDialogFragment dialog, Lifecycle lifecycle, int slotId)212     public SimStatusDialogController(@NonNull SimStatusDialogFragment dialog, Lifecycle lifecycle,
213             int slotId) {
214         mDialog = dialog;
215         mContext = dialog.getContext();
216         mSlotIndex = slotId;
217         mSubscriptionInfo = getPhoneSubscriptionInfo(slotId);
218 
219         mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
220         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
221         mEuiccManager = mContext.getSystemService(EuiccManager.class);
222         mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
223 
224         mRes = mContext.getResources();
225 
226         if (lifecycle != null) {
227             lifecycle.addObserver(this);
228         }
229     }
230 
231     @VisibleForTesting
getTelephonyManager()232     public TelephonyManager getTelephonyManager() {
233         return mTelephonyManager;
234     }
235 
initialize()236     public void initialize() {
237         requestForUpdateEid();
238 
239         if (mSubscriptionInfo == null) {
240             return;
241         }
242         mTelephonyManager =
243             getTelephonyManager().createForSubscriptionId(mSubscriptionInfo.getSubscriptionId());
244         mTelephonyCallback = new SimStatusDialogTelephonyCallback();
245         updateLatestAreaInfo();
246         updateSubscriptionStatus();
247     }
248 
updateSubscriptionStatus()249     private void updateSubscriptionStatus() {
250         updateNetworkProvider();
251 
252         // getServiceState() may return null when the subscription is inactive
253         // or when there was an error communicating with the phone process.
254         final ServiceState serviceState = getTelephonyManager().getServiceState();
255         final SignalStrength signalStrength = getTelephonyManager().getSignalStrength();
256 
257         updatePhoneNumber();
258         updateServiceState(serviceState);
259         updateSignalStrength(signalStrength);
260         updateNetworkType();
261         updateRoamingStatus(serviceState);
262         updateIccidNumber();
263         updateImsRegistrationState();
264     }
265 
266     /**
267      * Deinitialization works
268      */
deinitialize()269     public void deinitialize() {
270         if (mShowLatestAreaInfo) {
271             if (mCellBroadcastServiceConnection != null
272                     && mCellBroadcastServiceConnection.getService() != null) {
273                 mContext.unbindService(mCellBroadcastServiceConnection);
274             }
275             mCellBroadcastServiceConnection = null;
276         }
277     }
278 
279     /**
280      * OnResume lifecycle event, resume listening for phone state or subscription changes.
281      */
282     @OnLifecycleEvent(Event.ON_RESUME)
onResume()283     public void onResume() {
284         if (mSubscriptionInfo == null) {
285             return;
286         }
287         mTelephonyManager = getTelephonyManager().createForSubscriptionId(
288                 mSubscriptionInfo.getSubscriptionId());
289         getTelephonyManager()
290                 .registerTelephonyCallback(mContext.getMainExecutor(), mTelephonyCallback);
291         mSubscriptionManager.addOnSubscriptionsChangedListener(
292                 mContext.getMainExecutor(), mOnSubscriptionsChangedListener);
293         registerImsRegistrationCallback(mSubscriptionInfo.getSubscriptionId());
294 
295         if (mShowLatestAreaInfo) {
296             updateAreaInfoText();
297             mContext.registerReceiver(mAreaInfoReceiver,
298                     new IntentFilter(CellBroadcastIntents.ACTION_AREA_INFO_UPDATED));
299         }
300 
301         mIsRegisteredListener = true;
302     }
303 
304     /**
305      * onPause lifecycle event, no longer listen for phone state or subscription changes.
306      */
307     @OnLifecycleEvent(Event.ON_PAUSE)
onPause()308     public void onPause() {
309         if (mSubscriptionInfo == null) {
310             if (mIsRegisteredListener) {
311                 mSubscriptionManager.removeOnSubscriptionsChangedListener(
312                         mOnSubscriptionsChangedListener);
313                 getTelephonyManager().unregisterTelephonyCallback(mTelephonyCallback);
314                 if (mShowLatestAreaInfo) {
315                     mContext.unregisterReceiver(mAreaInfoReceiver);
316                 }
317                 mIsRegisteredListener = false;
318             }
319             return;
320         }
321 
322         unregisterImsRegistrationCallback(mSubscriptionInfo.getSubscriptionId());
323         mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
324         getTelephonyManager().unregisterTelephonyCallback(mTelephonyCallback);
325 
326         if (mShowLatestAreaInfo) {
327             mContext.unregisterReceiver(mAreaInfoReceiver);
328         }
329     }
330 
updateNetworkProvider()331     private void updateNetworkProvider() {
332         final CharSequence carrierName =
333                 mSubscriptionInfo != null ? mSubscriptionInfo.getCarrierName() : null;
334         mDialog.setText(NETWORK_PROVIDER_VALUE_ID, carrierName);
335     }
336 
337     @VisibleForTesting
updatePhoneNumber()338     public void updatePhoneNumber() {
339         // If formattedNumber is null or empty, it'll display as "Unknown".
340         mDialog.setText(PHONE_NUMBER_VALUE_ID,
341                 DeviceInfoUtils.getBidiFormattedPhoneNumber(mContext, mSubscriptionInfo));
342     }
343 
updateDataState(int state)344     private void updateDataState(int state) {
345         String networkStateValue;
346 
347         switch (state) {
348             case TelephonyManager.DATA_CONNECTED:
349                 networkStateValue = mRes.getString(R.string.radioInfo_data_connected);
350                 break;
351             case TelephonyManager.DATA_SUSPENDED:
352                 networkStateValue = mRes.getString(R.string.radioInfo_data_suspended);
353                 break;
354             case TelephonyManager.DATA_CONNECTING:
355                 networkStateValue = mRes.getString(R.string.radioInfo_data_connecting);
356                 break;
357             case TelephonyManager.DATA_DISCONNECTED:
358                 networkStateValue = mRes.getString(R.string.radioInfo_data_disconnected);
359                 break;
360             default:
361                 networkStateValue = mRes.getString(R.string.radioInfo_unknown);
362                 break;
363         }
364 
365         mDialog.setText(CELLULAR_NETWORK_STATE, networkStateValue);
366     }
367 
368     /**
369      * Update area info text retrieved from
370      * {@link CellBroadcastService#getCellBroadcastAreaInfo(int)}
371      */
updateAreaInfoText()372     private void updateAreaInfoText() {
373         if (!mShowLatestAreaInfo || mCellBroadcastServiceConnection == null) return;
374         ICellBroadcastService cellBroadcastService =
375                 ICellBroadcastService.Stub.asInterface(
376                         mCellBroadcastServiceConnection.getService());
377         if (cellBroadcastService == null) return;
378         try {
379             mDialog.setText(OPERATOR_INFO_VALUE_ID,
380                     cellBroadcastService.getCellBroadcastAreaInfo(mSlotIndex));
381 
382         } catch (RemoteException e) {
383             Log.d(TAG, "Can't get area info. e=" + e);
384         }
385     }
386 
387     /**
388      * Bind cell broadcast service.
389      */
bindCellBroadcastService()390     private void bindCellBroadcastService() {
391         mCellBroadcastServiceConnection = new CellBroadcastServiceConnection();
392         Intent intent = new Intent(CellBroadcastService.CELL_BROADCAST_SERVICE_INTERFACE);
393         String cbsPackage = getCellBroadcastServicePackage();
394         if (TextUtils.isEmpty(cbsPackage)) return;
395         intent.setPackage(cbsPackage);
396         if (mCellBroadcastServiceConnection != null
397                 && mCellBroadcastServiceConnection.getService() == null) {
398             if (!mContext.bindService(intent, mCellBroadcastServiceConnection,
399                     Context.BIND_AUTO_CREATE)) {
400                 Log.e(TAG, "Unable to bind to service");
401             }
402         } else {
403             Log.d(TAG, "skipping bindService because connection already exists");
404         }
405     }
406 
407     /** Returns the package name of the cell broadcast service, or null if there is none. */
getCellBroadcastServicePackage()408     private String getCellBroadcastServicePackage() {
409         PackageManager packageManager = mContext.getPackageManager();
410         List<ResolveInfo> cbsPackages = packageManager.queryIntentServices(
411                 new Intent(CellBroadcastService.CELL_BROADCAST_SERVICE_INTERFACE),
412                 PackageManager.MATCH_SYSTEM_ONLY);
413         if (cbsPackages.size() != 1) {
414             Log.e(TAG, "getCellBroadcastServicePackageName: found " + cbsPackages.size()
415                     + " CBS packages");
416         }
417         for (ResolveInfo info : cbsPackages) {
418             if (info.serviceInfo == null) continue;
419             String packageName = info.serviceInfo.packageName;
420             if (!TextUtils.isEmpty(packageName)) {
421                 if (packageManager.checkPermission(
422                         android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
423                         packageName) == PackageManager.PERMISSION_GRANTED) {
424                     Log.d(TAG, "getCellBroadcastServicePackageName: " + packageName);
425                     return packageName;
426                 } else {
427                     Log.e(TAG, "getCellBroadcastServicePackageName: " + packageName
428                             + " does not have READ_PRIVILEGED_PHONE_STATE permission");
429                 }
430             } else {
431                 Log.e(TAG, "getCellBroadcastServicePackageName: found a CBS package but "
432                         + "packageName is null/empty");
433             }
434         }
435         Log.e(TAG, "getCellBroadcastServicePackageName: package name not found");
436         return null;
437     }
438 
updateLatestAreaInfo()439     private void updateLatestAreaInfo() {
440         mShowLatestAreaInfo = Resources.getSystem().getBoolean(
441                 com.android.internal.R.bool.config_showAreaUpdateInfoSettings)
442                 && getTelephonyManager().getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA;
443 
444         if (mShowLatestAreaInfo) {
445             // Bind cell broadcast service to get the area info. The info will be updated once
446             // the service is connected.
447             bindCellBroadcastService();
448         } else {
449             mDialog.removeSettingFromScreen(OPERATOR_INFO_LABEL_ID);
450             mDialog.removeSettingFromScreen(OPERATOR_INFO_VALUE_ID);
451         }
452     }
453 
updateServiceState(ServiceState serviceState)454     private void updateServiceState(ServiceState serviceState) {
455         final int state = Utils.getCombinedServiceState(serviceState);
456         if (!Utils.isInService(serviceState)) {
457             resetSignalStrength();
458         } else if (!Utils.isInService(mPreviousServiceState)) {
459             // If ServiceState changed from out of service -> in service, update signal strength.
460             updateSignalStrength(getTelephonyManager().getSignalStrength());
461         }
462 
463         String serviceStateValue;
464 
465         switch (state) {
466             case ServiceState.STATE_IN_SERVICE:
467                 serviceStateValue = mRes.getString(R.string.radioInfo_service_in);
468                 break;
469             case ServiceState.STATE_OUT_OF_SERVICE:
470             case ServiceState.STATE_EMERGENCY_ONLY:
471                 // Set summary string of service state to radioInfo_service_out when
472                 // service state is both STATE_OUT_OF_SERVICE & STATE_EMERGENCY_ONLY
473                 serviceStateValue = mRes.getString(R.string.radioInfo_service_out);
474                 break;
475             case ServiceState.STATE_POWER_OFF:
476                 serviceStateValue = mRes.getString(R.string.radioInfo_service_off);
477                 break;
478             default:
479                 serviceStateValue = mRes.getString(R.string.radioInfo_unknown);
480                 break;
481         }
482 
483         mDialog.setText(SERVICE_STATE_VALUE_ID, serviceStateValue);
484     }
485 
updateSignalStrength(SignalStrength signalStrength)486     private void updateSignalStrength(SignalStrength signalStrength) {
487         if (signalStrength == null) {
488             return;
489         }
490         // by default we show the signal strength
491         boolean showSignalStrength = true;
492         if (mSubscriptionInfo != null) {
493             final int subscriptionId = mSubscriptionInfo.getSubscriptionId();
494             final PersistableBundle carrierConfig =
495                     mCarrierConfigManager.getConfigForSubId(subscriptionId);
496             if (carrierConfig != null) {
497                 showSignalStrength = carrierConfig.getBoolean(
498                         CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL);
499             }
500         }
501         if (!showSignalStrength) {
502             mDialog.removeSettingFromScreen(SIGNAL_STRENGTH_LABEL_ID);
503             mDialog.removeSettingFromScreen(SIGNAL_STRENGTH_VALUE_ID);
504             return;
505         }
506 
507         ServiceState serviceState = getTelephonyManager().getServiceState();
508         if (!Utils.isInService(serviceState)) {
509             return;
510         }
511 
512         int signalDbm = getDbm(signalStrength);
513         int signalAsu = getAsuLevel(signalStrength);
514 
515         if (signalDbm == -1) {
516             signalDbm = 0;
517         }
518 
519         if (signalAsu == -1) {
520             signalAsu = 0;
521         }
522 
523         mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, mRes.getString(R.string.sim_signal_strength,
524                 signalDbm, signalAsu));
525     }
526 
resetSignalStrength()527     private void resetSignalStrength() {
528         mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, "0");
529     }
530 
updateNetworkType()531     private void updateNetworkType() {
532         // TODO: all of this should be based on TelephonyDisplayInfo instead of just the 5G logic
533         if (mSubscriptionInfo == null) {
534             final String unknownNetworkType =
535                     getNetworkTypeName(TelephonyManager.NETWORK_TYPE_UNKNOWN);
536             mDialog.setText(CELL_VOICE_NETWORK_TYPE_VALUE_ID, unknownNetworkType);
537             mDialog.setText(CELL_DATA_NETWORK_TYPE_VALUE_ID, unknownNetworkType);
538             return;
539         }
540 
541         // Whether EDGE, UMTS, etc...
542         String dataNetworkTypeName = null;
543         String voiceNetworkTypeName = null;
544         final int subId = mSubscriptionInfo.getSubscriptionId();
545         final int actualDataNetworkType = getTelephonyManager().getDataNetworkType();
546         final int actualVoiceNetworkType = getTelephonyManager().getVoiceNetworkType();
547         final int overrideNetworkType = mTelephonyDisplayInfo == null
548                 ? TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
549                 : mTelephonyDisplayInfo.getOverrideNetworkType();
550 
551         if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) {
552             dataNetworkTypeName = getNetworkTypeName(actualDataNetworkType);
553         }
554         if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) {
555             voiceNetworkTypeName = getNetworkTypeName(actualVoiceNetworkType);
556         }
557 
558         final boolean isOverrideNwTypeNrAdvancedOrNsa =
559                 overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED
560                         || overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA;
561         if (actualDataNetworkType == TelephonyManager.NETWORK_TYPE_LTE
562                 && isOverrideNwTypeNrAdvancedOrNsa) {
563             dataNetworkTypeName = "NR NSA";
564         }
565 
566         boolean show4GForLTE = false;
567         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId);
568         if (carrierConfig != null) {
569             show4GForLTE = carrierConfig.getBoolean(
570                     CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
571         }
572 
573         if (show4GForLTE) {
574             if ("LTE".equals(dataNetworkTypeName)) {
575                 dataNetworkTypeName = "4G";
576             }
577             if ("LTE".equals(voiceNetworkTypeName)) {
578                 voiceNetworkTypeName = "4G";
579             }
580         }
581 
582         mDialog.setText(CELL_VOICE_NETWORK_TYPE_VALUE_ID, voiceNetworkTypeName);
583         mDialog.setText(CELL_DATA_NETWORK_TYPE_VALUE_ID, dataNetworkTypeName);
584     }
585 
updateRoamingStatus(ServiceState serviceState)586     private void updateRoamingStatus(ServiceState serviceState) {
587         // If the serviceState is null, we assume that roaming is disabled.
588         if (serviceState == null) {
589             mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_unknown));
590         } else if (serviceState.getRoaming()) {
591             mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_in));
592         } else {
593             mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_not));
594         }
595     }
596 
updateIccidNumber()597     private void updateIccidNumber() {
598         // do not show iccid by default
599         boolean showIccId = false;
600         if (mSubscriptionInfo != null) {
601             final int subscriptionId = mSubscriptionInfo.getSubscriptionId();
602             final PersistableBundle carrierConfig =
603                     mCarrierConfigManager.getConfigForSubId(subscriptionId);
604             if (carrierConfig != null) {
605                 showIccId = carrierConfig.getBoolean(
606                         CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL);
607             }
608         }
609         if (!showIccId) {
610             mDialog.removeSettingFromScreen(ICCID_INFO_LABEL_ID);
611             mDialog.removeSettingFromScreen(ICCID_INFO_VALUE_ID);
612         } else {
613             mDialog.setText(ICCID_INFO_VALUE_ID, getTelephonyManager().getSimSerialNumber());
614         }
615     }
616 
617     @VisibleForTesting
requestForUpdateEid()618     protected void requestForUpdateEid() {
619         ThreadUtils.postOnBackgroundThread(() -> {
620             final AtomicReference<String> eid = getEid(mSlotIndex);
621             ThreadUtils.postOnMainThread(() -> updateEid(eid));
622         });
623     }
624 
625     @VisibleForTesting
getEid(int slotIndex)626     public AtomicReference<String> getEid(int slotIndex) {
627         boolean shouldHaveEid = false;
628         String eid = null;
629         if (getTelephonyManager().getActiveModemCount() > MAX_PHONE_COUNT_SINGLE_SIM) {
630             // Get EID per-SIM in multi-SIM mode
631             final Map<Integer, Integer> mapping = mTelephonyManager
632                     .getLogicalToPhysicalSlotMapping();
633             final int pSlotId = mapping.getOrDefault(slotIndex,
634                     SubscriptionManager.INVALID_SIM_SLOT_INDEX);
635 
636             if (pSlotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
637                 final List<UiccCardInfo> infos = getTelephonyManager().getUiccCardsInfo();
638 
639                 for (UiccCardInfo info : infos) {
640                     if (info.getSlotIndex() == pSlotId) {
641                         if (info.isEuicc()) {
642                             shouldHaveEid = true;
643                             eid = info.getEid();
644                             if (TextUtils.isEmpty(eid)) {
645                                 eid = mEuiccManager.createForCardId(info.getCardId()).getEid();
646                             }
647                         }
648                         break;
649                     }
650                 }
651             }
652         } else if (mEuiccManager.isEnabled()) {
653             // Get EID of default eSIM in single-SIM mode
654             shouldHaveEid = true;
655             eid = mEuiccManager.getEid();
656         }
657         if ((!shouldHaveEid) && (eid == null)) {
658             return null;
659         }
660         return new AtomicReference<String>(eid);
661     }
662 
663     @VisibleForTesting
updateEid(AtomicReference<String> eid)664     protected void updateEid(AtomicReference<String> eid) {
665         if (eid == null) {
666             mDialog.removeSettingFromScreen(EID_INFO_LABEL_ID);
667             mDialog.removeSettingFromScreen(EID_INFO_VALUE_ID);
668         } else if (eid.get() != null) {
669             mDialog.setText(EID_INFO_VALUE_ID, eid.get());
670         }
671     }
672 
isImsRegistrationStateShowUp()673     private boolean isImsRegistrationStateShowUp() {
674         if (mSubscriptionInfo == null) {
675             return false;
676         }
677         final int subscriptionId = mSubscriptionInfo.getSubscriptionId();
678         final PersistableBundle carrierConfig =
679                 mCarrierConfigManager.getConfigForSubId(subscriptionId);
680         return carrierConfig == null ? false :
681                 carrierConfig.getBoolean(
682                         CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL);
683     }
684 
updateImsRegistrationState()685     private void updateImsRegistrationState() {
686         if (isImsRegistrationStateShowUp()) {
687             return;
688         }
689         mDialog.removeSettingFromScreen(IMS_REGISTRATION_STATE_LABEL_ID);
690         mDialog.removeSettingFromScreen(IMS_REGISTRATION_STATE_VALUE_ID);
691     }
692 
693     private ImsMmTelManager.RegistrationCallback mImsRegStateCallback =
694             new ImsMmTelManager.RegistrationCallback() {
695         @Override
696         public void onRegistered(@AccessNetworkConstants.TransportType int imsTransportType) {
697             mDialog.setText(IMS_REGISTRATION_STATE_VALUE_ID, mRes.getString(
698                     R.string.ims_reg_status_registered));
699         }
700         @Override
701         public void onRegistering(@AccessNetworkConstants.TransportType int imsTransportType) {
702             mDialog.setText(IMS_REGISTRATION_STATE_VALUE_ID, mRes.getString(
703                     R.string.ims_reg_status_not_registered));
704         }
705         @Override
706         public void onUnregistered(@Nullable ImsReasonInfo info) {
707             mDialog.setText(IMS_REGISTRATION_STATE_VALUE_ID, mRes.getString(
708                     R.string.ims_reg_status_not_registered));
709         }
710         @Override
711         public void onTechnologyChangeFailed(
712                 @AccessNetworkConstants.TransportType int imsTransportType,
713                 @Nullable ImsReasonInfo info) {
714             mDialog.setText(IMS_REGISTRATION_STATE_VALUE_ID, mRes.getString(
715                     R.string.ims_reg_status_not_registered));
716         }
717     };
718 
registerImsRegistrationCallback(int subId)719     private void registerImsRegistrationCallback(int subId) {
720         if (!isImsRegistrationStateShowUp()) {
721             return;
722         }
723         try {
724             final ImsMmTelManager imsMmTelMgr = ImsMmTelManager.createForSubscriptionId(subId);
725             imsMmTelMgr.registerImsRegistrationCallback(mDialog.getContext().getMainExecutor(),
726                     mImsRegStateCallback);
727         } catch (ImsException exception) {
728             Log.w(TAG, "fail to register IMS status for subId=" + subId, exception);
729         }
730     }
731 
unregisterImsRegistrationCallback(int subId)732     private void unregisterImsRegistrationCallback(int subId) {
733         if (!isImsRegistrationStateShowUp()) {
734             return;
735         }
736         final ImsMmTelManager imsMmTelMgr = ImsMmTelManager.createForSubscriptionId(subId);
737         imsMmTelMgr.unregisterImsRegistrationCallback(mImsRegStateCallback);
738     }
739 
getPhoneSubscriptionInfo(int slotId)740     private SubscriptionInfo getPhoneSubscriptionInfo(int slotId) {
741         return SubscriptionManager.from(mContext).getActiveSubscriptionInfoForSimSlotIndex(slotId);
742     }
743 
getDbm(SignalStrength signalStrength)744     private int getDbm(SignalStrength signalStrength) {
745         List<CellSignalStrength> cellSignalStrengthList = signalStrength.getCellSignalStrengths();
746         int dbm = -1;
747         if (cellSignalStrengthList == null) {
748             return dbm;
749         }
750 
751         for (CellSignalStrength cell : cellSignalStrengthList) {
752             if (cell.getDbm() != -1) {
753                 dbm = cell.getDbm();
754                 break;
755             }
756         }
757 
758         return dbm;
759     }
760 
getAsuLevel(SignalStrength signalStrength)761     private int getAsuLevel(SignalStrength signalStrength) {
762         List<CellSignalStrength> cellSignalStrengthList = signalStrength.getCellSignalStrengths();
763         int asu = -1;
764         if (cellSignalStrengthList == null) {
765             return asu;
766         }
767 
768         for (CellSignalStrength cell : cellSignalStrengthList) {
769             if (cell.getAsuLevel() != -1) {
770                 asu = cell.getAsuLevel();
771                 break;
772             }
773         }
774 
775         return asu;
776     }
777 
778     @VisibleForTesting
779     class SimStatusDialogTelephonyCallback extends TelephonyCallback implements
780             TelephonyCallback.DataConnectionStateListener,
781             TelephonyCallback.SignalStrengthsListener,
782             TelephonyCallback.ServiceStateListener,
783             TelephonyCallback.DisplayInfoListener {
784         @Override
onDataConnectionStateChanged(int state, int networkType)785         public void onDataConnectionStateChanged(int state, int networkType) {
786             updateDataState(state);
787             updateNetworkType();
788         }
789 
790         @Override
onSignalStrengthsChanged(SignalStrength signalStrength)791         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
792             updateSignalStrength(signalStrength);
793         }
794 
795         @Override
onServiceStateChanged(ServiceState serviceState)796         public void onServiceStateChanged(ServiceState serviceState) {
797             updateNetworkProvider();
798             updateServiceState(serviceState);
799             updateRoamingStatus(serviceState);
800             mPreviousServiceState = serviceState;
801         }
802 
803         @Override
onDisplayInfoChanged(@onNull TelephonyDisplayInfo displayInfo)804         public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo displayInfo) {
805             mTelephonyDisplayInfo = displayInfo;
806             updateNetworkType();
807         }
808     }
809 
810     @VisibleForTesting
getNetworkTypeName(@nnotation.NetworkType int type)811     static String getNetworkTypeName(@Annotation.NetworkType int type) {
812         switch (type) {
813             case TelephonyManager.NETWORK_TYPE_GPRS:
814                 return "GPRS";
815             case TelephonyManager.NETWORK_TYPE_EDGE:
816                 return "EDGE";
817             case TelephonyManager.NETWORK_TYPE_UMTS:
818                 return "UMTS";
819             case TelephonyManager.NETWORK_TYPE_HSDPA:
820                 return "HSDPA";
821             case TelephonyManager.NETWORK_TYPE_HSUPA:
822                 return "HSUPA";
823             case TelephonyManager.NETWORK_TYPE_HSPA:
824                 return "HSPA";
825             case TelephonyManager.NETWORK_TYPE_CDMA:
826                 return "CDMA";
827             case TelephonyManager.NETWORK_TYPE_EVDO_0:
828                 return "CDMA - EvDo rev. 0";
829             case TelephonyManager.NETWORK_TYPE_EVDO_A:
830                 return "CDMA - EvDo rev. A";
831             case TelephonyManager.NETWORK_TYPE_EVDO_B:
832                 return "CDMA - EvDo rev. B";
833             case TelephonyManager.NETWORK_TYPE_1xRTT:
834                 return "CDMA - 1xRTT";
835             case TelephonyManager.NETWORK_TYPE_LTE:
836                 return "LTE";
837             case TelephonyManager.NETWORK_TYPE_EHRPD:
838                 return "CDMA - eHRPD";
839             case TelephonyManager.NETWORK_TYPE_IDEN:
840                 return "iDEN";
841             case TelephonyManager.NETWORK_TYPE_HSPAP:
842                 return "HSPA+";
843             case TelephonyManager.NETWORK_TYPE_GSM:
844                 return "GSM";
845             case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
846                 return "TD_SCDMA";
847             case TelephonyManager.NETWORK_TYPE_IWLAN:
848                 return "IWLAN";
849 //          case TelephonyManager.NETWORK_TYPE_LTE_CA:
850 //              return "LTE_CA";
851             case TelephonyManager.NETWORK_TYPE_NR:
852                 return "NR SA";
853             default:
854                 return "UNKNOWN";
855         }
856     }
857 }
858