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 android.content.BroadcastReceiver;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.ServiceConnection;
25 import android.content.pm.PackageManager;
26 import android.content.pm.ResolveInfo;
27 import android.content.res.Resources;
28 import android.os.IBinder;
29 import android.os.PersistableBundle;
30 import android.os.RemoteException;
31 import android.telephony.Annotation;
32 import android.telephony.CarrierConfigManager;
33 import android.telephony.CellBroadcastIntents;
34 import android.telephony.CellBroadcastService;
35 import android.telephony.ICellBroadcastService;
36 import android.telephony.ServiceState;
37 import android.telephony.SubscriptionInfo;
38 import android.telephony.SubscriptionManager;
39 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
40 import android.telephony.TelephonyCallback;
41 import android.telephony.TelephonyDisplayInfo;
42 import android.telephony.TelephonyManager;
43 import android.telephony.euicc.EuiccManager;
44 import android.text.TextUtils;
45 import android.util.Log;
46 
47 import androidx.annotation.NonNull;
48 import androidx.annotation.Nullable;
49 import androidx.annotation.VisibleForTesting;
50 import androidx.lifecycle.DefaultLifecycleObserver;
51 import androidx.lifecycle.LifecycleOwner;
52 
53 import com.android.settings.R;
54 import com.android.settings.network.SubscriptionUtil;
55 import com.android.settingslib.Utils;
56 import com.android.settingslib.core.lifecycle.Lifecycle;
57 
58 import kotlin.Unit;
59 
60 import java.util.List;
61 
62 /**
63  * Controller for Sim Status information within the About Phone Settings page.
64  */
65 public class SimStatusDialogController implements DefaultLifecycleObserver {
66 
67     private final static String TAG = "SimStatusDialogCtrl";
68 
69     @VisibleForTesting
70     final static int NETWORK_PROVIDER_VALUE_ID = R.id.operator_name_value;
71     @VisibleForTesting
72     final static int PHONE_NUMBER_VALUE_ID = R.id.number_value;
73     @VisibleForTesting
74     final static int CELLULAR_NETWORK_STATE = R.id.data_state_value;
75     @VisibleForTesting
76     final static int OPERATOR_INFO_LABEL_ID = R.id.latest_area_info_label;
77     @VisibleForTesting
78     final static int OPERATOR_INFO_VALUE_ID = R.id.latest_area_info_value;
79     @VisibleForTesting
80     final static int SERVICE_STATE_VALUE_ID = R.id.service_state_value;
81     @VisibleForTesting
82     final static int SIGNAL_STRENGTH_LABEL_ID = R.id.signal_strength_label;
83     @VisibleForTesting
84     final static int SIGNAL_STRENGTH_VALUE_ID = R.id.signal_strength_value;
85     @VisibleForTesting
86     final static int CELL_VOICE_NETWORK_TYPE_VALUE_ID = R.id.voice_network_type_value;
87     @VisibleForTesting
88     final static int CELL_DATA_NETWORK_TYPE_VALUE_ID = R.id.data_network_type_value;
89     @VisibleForTesting
90     final static int ROAMING_INFO_VALUE_ID = R.id.roaming_state_value;
91     @VisibleForTesting
92     final static int ICCID_INFO_LABEL_ID = R.id.icc_id_label;
93     @VisibleForTesting
94     final static int ICCID_INFO_VALUE_ID = R.id.icc_id_value;
95     @VisibleForTesting
96     final static int IMS_REGISTRATION_STATE_LABEL_ID = R.id.ims_reg_state_label;
97     @VisibleForTesting
98     final static int IMS_REGISTRATION_STATE_VALUE_ID = R.id.ims_reg_state_value;
99 
100     @VisibleForTesting
101     static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
102 
103     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
104             new OnSubscriptionsChangedListener() {
105                 @Override
106                 public void onSubscriptionsChanged() {
107                     mSubscriptionInfo = getPhoneSubscriptionInfo(mSlotIndex);
108                     updateSubscriptionStatus();
109                 }
110             };
111 
112     private SubscriptionInfo mSubscriptionInfo;
113     private TelephonyDisplayInfo mTelephonyDisplayInfo;
114 
115     private final int mSlotIndex;
116     private TelephonyManager mTelephonyManager;
117 
118     private final SimStatusDialogFragment mDialog;
119     private final SubscriptionManager mSubscriptionManager;
120     private final CarrierConfigManager mCarrierConfigManager;
121     private final EuiccManager mEuiccManager;
122     private final Resources mRes;
123     private final Context mContext;
124 
125     private boolean mShowLatestAreaInfo;
126     private boolean mIsRegisteredListener = false;
127 
128     private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() {
129         @Override
130         public void onReceive(Context context, Intent intent) {
131             if (CellBroadcastIntents.ACTION_AREA_INFO_UPDATED.equals(intent.getAction())
132                     && intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0)
133                     == mSlotIndex) {
134                 updateAreaInfoText();
135             }
136         }
137     };
138 
139     @VisibleForTesting
140     protected SimStatusDialogTelephonyCallback mTelephonyCallback;
141 
142     private CellBroadcastServiceConnection mCellBroadcastServiceConnection;
143 
144     private class CellBroadcastServiceConnection implements ServiceConnection {
145         private IBinder mService;
146 
147         @Nullable
getService()148         public IBinder getService() {
149             return mService;
150         }
151 
152         @Override
onServiceConnected(ComponentName className, IBinder service)153         public void onServiceConnected(ComponentName className, IBinder service) {
154             Log.d(TAG, "connected to CellBroadcastService");
155             this.mService = service;
156             updateAreaInfoText();
157         }
158 
159         @Override
onServiceDisconnected(ComponentName className)160         public void onServiceDisconnected(ComponentName className) {
161             this.mService = null;
162             Log.d(TAG, "mICellBroadcastService has disconnected unexpectedly");
163         }
164 
165         @Override
onBindingDied(ComponentName name)166         public void onBindingDied(ComponentName name) {
167             this.mService = null;
168             Log.d(TAG, "Binding died");
169         }
170 
171         @Override
onNullBinding(ComponentName name)172         public void onNullBinding(ComponentName name) {
173             this.mService = null;
174             Log.d(TAG, "Null binding");
175         }
176     }
177 
SimStatusDialogController(@onNull SimStatusDialogFragment dialog, Lifecycle lifecycle, int slotId)178     public SimStatusDialogController(@NonNull SimStatusDialogFragment dialog, Lifecycle lifecycle,
179             int slotId) {
180         mDialog = dialog;
181         mContext = dialog.getContext();
182         mSlotIndex = slotId;
183         mSubscriptionInfo = getPhoneSubscriptionInfo(slotId);
184 
185         mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
186         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
187         mEuiccManager = mContext.getSystemService(EuiccManager.class);
188         mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
189 
190         mRes = mContext.getResources();
191 
192         if (lifecycle != null) {
193             lifecycle.addObserver(this);
194         }
195     }
196 
197     @VisibleForTesting
getTelephonyManager()198     public TelephonyManager getTelephonyManager() {
199         return mTelephonyManager;
200     }
201 
initialize()202     public void initialize() {
203         if (mSubscriptionInfo == null) {
204             return;
205         }
206         mTelephonyManager =
207             getTelephonyManager().createForSubscriptionId(mSubscriptionInfo.getSubscriptionId());
208         mTelephonyCallback = new SimStatusDialogTelephonyCallback();
209         updateLatestAreaInfo();
210         updateSubscriptionStatus();
211     }
212 
updateSubscriptionStatus()213     private void updateSubscriptionStatus() {
214         updateNetworkProvider();
215 
216         // getServiceState() may return null when the subscription is inactive
217         // or when there was an error communicating with the phone process.
218         final ServiceState serviceState = getTelephonyManager().getServiceState();
219 
220         updatePhoneNumber();
221         updateServiceState(serviceState);
222         updateNetworkType();
223         updateRoamingStatus(serviceState);
224         updateIccidNumber();
225     }
226 
227     /**
228      * Deinitialization works
229      */
deinitialize()230     public void deinitialize() {
231         if (mShowLatestAreaInfo) {
232             if (mCellBroadcastServiceConnection != null
233                     && mCellBroadcastServiceConnection.getService() != null) {
234                 mContext.unbindService(mCellBroadcastServiceConnection);
235             }
236             mCellBroadcastServiceConnection = null;
237         }
238     }
239 
240     /**
241      * OnResume lifecycle event, resume listening for phone state or subscription changes.
242      */
243     @Override
onResume(@onNull LifecycleOwner owner)244     public void onResume(@NonNull LifecycleOwner owner) {
245         if (mSubscriptionInfo == null) {
246             return;
247         }
248         mTelephonyManager = getTelephonyManager().createForSubscriptionId(
249                 mSubscriptionInfo.getSubscriptionId());
250         getTelephonyManager()
251                 .registerTelephonyCallback(mContext.getMainExecutor(), mTelephonyCallback);
252         mSubscriptionManager.addOnSubscriptionsChangedListener(
253                 mContext.getMainExecutor(), mOnSubscriptionsChangedListener);
254         collectSimStatusDialogInfo(owner);
255 
256         if (mShowLatestAreaInfo) {
257             updateAreaInfoText();
258             mContext.registerReceiver(mAreaInfoReceiver,
259                     new IntentFilter(CellBroadcastIntents.ACTION_AREA_INFO_UPDATED),
260                     Context.RECEIVER_EXPORTED/*UNAUDITED*/);
261         }
262 
263         mIsRegisteredListener = true;
264     }
265 
266     /**
267      * onPause lifecycle event, no longer listen for phone state or subscription changes.
268      */
269     @Override
onPause(@onNull LifecycleOwner owner)270     public void onPause(@NonNull LifecycleOwner owner) {
271         if (mSubscriptionInfo == null) {
272             if (mIsRegisteredListener) {
273                 mSubscriptionManager.removeOnSubscriptionsChangedListener(
274                         mOnSubscriptionsChangedListener);
275                 getTelephonyManager().unregisterTelephonyCallback(mTelephonyCallback);
276                 if (mShowLatestAreaInfo) {
277                     mContext.unregisterReceiver(mAreaInfoReceiver);
278                 }
279                 mIsRegisteredListener = false;
280             }
281             return;
282         }
283 
284         mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
285         getTelephonyManager().unregisterTelephonyCallback(mTelephonyCallback);
286 
287         if (mShowLatestAreaInfo) {
288             mContext.unregisterReceiver(mAreaInfoReceiver);
289         }
290     }
291 
updateNetworkProvider()292     private void updateNetworkProvider() {
293         final CharSequence carrierName =
294                 mSubscriptionInfo != null ? mSubscriptionInfo.getCarrierName() : null;
295         mDialog.setText(NETWORK_PROVIDER_VALUE_ID, carrierName);
296     }
297 
298     @VisibleForTesting
updatePhoneNumber()299     public void updatePhoneNumber() {
300         // If formattedNumber is null or empty, it'll display as "Unknown".
301         mDialog.setText(PHONE_NUMBER_VALUE_ID,
302                 SubscriptionUtil.getBidiFormattedPhoneNumber(mContext, mSubscriptionInfo));
303     }
304 
updateDataState(int state)305     private void updateDataState(int state) {
306         String networkStateValue;
307 
308         switch (state) {
309             case TelephonyManager.DATA_CONNECTED:
310                 networkStateValue = mRes.getString(R.string.radioInfo_data_connected);
311                 break;
312             case TelephonyManager.DATA_SUSPENDED:
313                 networkStateValue = mRes.getString(R.string.radioInfo_data_suspended);
314                 break;
315             case TelephonyManager.DATA_CONNECTING:
316                 networkStateValue = mRes.getString(R.string.radioInfo_data_connecting);
317                 break;
318             case TelephonyManager.DATA_DISCONNECTED:
319                 networkStateValue = mRes.getString(R.string.radioInfo_data_disconnected);
320                 break;
321             default:
322                 networkStateValue = mRes.getString(R.string.radioInfo_unknown);
323                 break;
324         }
325 
326         mDialog.setText(CELLULAR_NETWORK_STATE, networkStateValue);
327     }
328 
329     /**
330      * Update area info text retrieved from
331      * {@link CellBroadcastService#getCellBroadcastAreaInfo(int)}
332      */
updateAreaInfoText()333     private void updateAreaInfoText() {
334         if (!mShowLatestAreaInfo || mCellBroadcastServiceConnection == null) return;
335         ICellBroadcastService cellBroadcastService =
336                 ICellBroadcastService.Stub.asInterface(
337                         mCellBroadcastServiceConnection.getService());
338         if (cellBroadcastService == null) return;
339         try {
340             mDialog.setText(OPERATOR_INFO_VALUE_ID,
341                     cellBroadcastService.getCellBroadcastAreaInfo(mSlotIndex));
342 
343         } catch (RemoteException e) {
344             Log.d(TAG, "Can't get area info. e=" + e);
345         }
346     }
347 
348     /**
349      * Bind cell broadcast service.
350      */
bindCellBroadcastService()351     private void bindCellBroadcastService() {
352         mCellBroadcastServiceConnection = new CellBroadcastServiceConnection();
353         Intent intent = new Intent(CellBroadcastService.CELL_BROADCAST_SERVICE_INTERFACE);
354         String cbsPackage = getCellBroadcastServicePackage();
355         if (TextUtils.isEmpty(cbsPackage)) return;
356         intent.setPackage(cbsPackage);
357         if (mCellBroadcastServiceConnection != null
358                 && mCellBroadcastServiceConnection.getService() == null) {
359             if (!mContext.bindService(intent, mCellBroadcastServiceConnection,
360                     Context.BIND_AUTO_CREATE)) {
361                 Log.e(TAG, "Unable to bind to service");
362             }
363         } else {
364             Log.d(TAG, "skipping bindService because connection already exists");
365         }
366     }
367 
368     /** Returns the package name of the cell broadcast service, or null if there is none. */
getCellBroadcastServicePackage()369     private String getCellBroadcastServicePackage() {
370         PackageManager packageManager = mContext.getPackageManager();
371         List<ResolveInfo> cbsPackages = packageManager.queryIntentServices(
372                 new Intent(CellBroadcastService.CELL_BROADCAST_SERVICE_INTERFACE),
373                 PackageManager.MATCH_SYSTEM_ONLY);
374         if (cbsPackages.size() != 1) {
375             Log.e(TAG, "getCellBroadcastServicePackageName: found " + cbsPackages.size()
376                     + " CBS packages");
377         }
378         for (ResolveInfo info : cbsPackages) {
379             if (info.serviceInfo == null) continue;
380             String packageName = info.serviceInfo.packageName;
381             if (!TextUtils.isEmpty(packageName)) {
382                 if (packageManager.checkPermission(
383                         android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
384                         packageName) == PackageManager.PERMISSION_GRANTED) {
385                     Log.d(TAG, "getCellBroadcastServicePackageName: " + packageName);
386                     return packageName;
387                 } else {
388                     Log.e(TAG, "getCellBroadcastServicePackageName: " + packageName
389                             + " does not have READ_PRIVILEGED_PHONE_STATE permission");
390                 }
391             } else {
392                 Log.e(TAG, "getCellBroadcastServicePackageName: found a CBS package but "
393                         + "packageName is null/empty");
394             }
395         }
396         Log.e(TAG, "getCellBroadcastServicePackageName: package name not found");
397         return null;
398     }
399 
updateLatestAreaInfo()400     private void updateLatestAreaInfo() {
401         mShowLatestAreaInfo = Resources.getSystem().getBoolean(
402                 com.android.internal.R.bool.config_showAreaUpdateInfoSettings)
403                 && getTelephonyManager().getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA;
404 
405         if (mShowLatestAreaInfo) {
406             // Bind cell broadcast service to get the area info. The info will be updated once
407             // the service is connected.
408             bindCellBroadcastService();
409         } else {
410             mDialog.removeSettingFromScreen(OPERATOR_INFO_LABEL_ID);
411             mDialog.removeSettingFromScreen(OPERATOR_INFO_VALUE_ID);
412         }
413     }
414 
updateServiceState(ServiceState serviceState)415     private void updateServiceState(ServiceState serviceState) {
416         final int state = Utils.getCombinedServiceState(serviceState);
417 
418         String serviceStateValue;
419 
420         switch (state) {
421             case ServiceState.STATE_IN_SERVICE:
422                 serviceStateValue = mRes.getString(R.string.radioInfo_service_in);
423                 break;
424             case ServiceState.STATE_OUT_OF_SERVICE:
425             case ServiceState.STATE_EMERGENCY_ONLY:
426                 // Set summary string of service state to radioInfo_service_out when
427                 // service state is both STATE_OUT_OF_SERVICE & STATE_EMERGENCY_ONLY
428                 serviceStateValue = mRes.getString(R.string.radioInfo_service_out);
429                 break;
430             case ServiceState.STATE_POWER_OFF:
431                 serviceStateValue = mRes.getString(R.string.radioInfo_service_off);
432                 break;
433             default:
434                 serviceStateValue = mRes.getString(R.string.radioInfo_unknown);
435                 break;
436         }
437 
438         mDialog.setText(SERVICE_STATE_VALUE_ID, serviceStateValue);
439     }
440 
updateSignalStrength(@ullable String signalStrength)441     private void updateSignalStrength(@Nullable String signalStrength) {
442         boolean isVisible = signalStrength != null;
443         mDialog.setSettingVisibility(SIGNAL_STRENGTH_LABEL_ID, isVisible);
444         mDialog.setSettingVisibility(SIGNAL_STRENGTH_VALUE_ID, isVisible);
445         mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, signalStrength);
446     }
447 
updateNetworkType()448     private void updateNetworkType() {
449         // TODO: all of this should be based on TelephonyDisplayInfo instead of just the 5G logic
450         if (mSubscriptionInfo == null) {
451             final String unknownNetworkType =
452                     getNetworkTypeName(TelephonyManager.NETWORK_TYPE_UNKNOWN);
453             mDialog.setText(CELL_VOICE_NETWORK_TYPE_VALUE_ID, unknownNetworkType);
454             mDialog.setText(CELL_DATA_NETWORK_TYPE_VALUE_ID, unknownNetworkType);
455             return;
456         }
457 
458         // Whether EDGE, UMTS, etc...
459         String dataNetworkTypeName = null;
460         String voiceNetworkTypeName = null;
461         final int subId = mSubscriptionInfo.getSubscriptionId();
462         final int actualDataNetworkType = getTelephonyManager().getDataNetworkType();
463         final int actualVoiceNetworkType = getTelephonyManager().getVoiceNetworkType();
464         final int overrideNetworkType = mTelephonyDisplayInfo == null
465                 ? TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
466                 : mTelephonyDisplayInfo.getOverrideNetworkType();
467 
468         if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) {
469             dataNetworkTypeName = getNetworkTypeName(actualDataNetworkType);
470         }
471         if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) {
472             voiceNetworkTypeName = getNetworkTypeName(actualVoiceNetworkType);
473         }
474 
475         final boolean isOverrideNwTypeNrAdvancedOrNsa =
476                 overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED
477                         || overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA;
478         if (actualDataNetworkType == TelephonyManager.NETWORK_TYPE_LTE
479                 && isOverrideNwTypeNrAdvancedOrNsa) {
480             dataNetworkTypeName = "NR NSA";
481         }
482 
483         boolean show4GForLTE = false;
484         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId);
485         if (carrierConfig != null) {
486             show4GForLTE = carrierConfig.getBoolean(
487                     CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
488         }
489 
490         if (show4GForLTE) {
491             if ("LTE".equals(dataNetworkTypeName)) {
492                 dataNetworkTypeName = "4G";
493             }
494             if ("LTE".equals(voiceNetworkTypeName)) {
495                 voiceNetworkTypeName = "4G";
496             }
497         }
498 
499         mDialog.setText(CELL_VOICE_NETWORK_TYPE_VALUE_ID, voiceNetworkTypeName);
500         mDialog.setText(CELL_DATA_NETWORK_TYPE_VALUE_ID, dataNetworkTypeName);
501     }
502 
updateRoamingStatus(ServiceState serviceState)503     private void updateRoamingStatus(ServiceState serviceState) {
504         // If the serviceState is null, we assume that roaming is disabled.
505         if (serviceState == null) {
506             mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_unknown));
507         } else if (serviceState.getRoaming()) {
508             mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_in));
509         } else {
510             mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_not));
511         }
512     }
513 
updateIccidNumber()514     private void updateIccidNumber() {
515         // do not show iccid by default
516         boolean showIccId = false;
517         if (mSubscriptionInfo != null) {
518             final int subscriptionId = mSubscriptionInfo.getSubscriptionId();
519             final PersistableBundle carrierConfig =
520                     mCarrierConfigManager.getConfigForSubId(subscriptionId);
521             if (carrierConfig != null) {
522                 showIccId = carrierConfig.getBoolean(
523                         CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL);
524             }
525         }
526         if (!showIccId) {
527             mDialog.removeSettingFromScreen(ICCID_INFO_LABEL_ID);
528             mDialog.removeSettingFromScreen(ICCID_INFO_VALUE_ID);
529         } else {
530             mDialog.setText(ICCID_INFO_VALUE_ID, getTelephonyManager().getSimSerialNumber());
531         }
532     }
533 
updateImsRegistrationState(@ullable Boolean imsRegistered)534     private void updateImsRegistrationState(@Nullable Boolean imsRegistered) {
535         boolean isVisible = imsRegistered != null;
536         mDialog.setSettingVisibility(IMS_REGISTRATION_STATE_LABEL_ID, isVisible);
537         mDialog.setSettingVisibility(IMS_REGISTRATION_STATE_VALUE_ID, isVisible);
538         int stringId = Boolean.TRUE.equals(imsRegistered)
539                 ? com.android.settingslib.R.string.ims_reg_status_registered
540                 : com.android.settingslib.R.string.ims_reg_status_not_registered;
541         mDialog.setText(IMS_REGISTRATION_STATE_VALUE_ID, mRes.getString(stringId));
542     }
543 
collectSimStatusDialogInfo(@onNull LifecycleOwner owner)544     private void collectSimStatusDialogInfo(@NonNull LifecycleOwner owner) {
545         new SimStatusDialogRepository(mContext).collectSimStatusDialogInfo(
546                 owner, mSlotIndex, (simStatusDialogInfo) -> {
547                     updateSignalStrength(simStatusDialogInfo.getSignalStrength());
548                     updateImsRegistrationState(simStatusDialogInfo.getImsRegistered());
549                     return Unit.INSTANCE;
550                 }
551         );
552     }
553 
getPhoneSubscriptionInfo(int slotId)554     private SubscriptionInfo getPhoneSubscriptionInfo(int slotId) {
555         return SubscriptionManager.from(mContext).getActiveSubscriptionInfoForSimSlotIndex(slotId);
556     }
557 
558     @VisibleForTesting
559     class SimStatusDialogTelephonyCallback extends TelephonyCallback implements
560             TelephonyCallback.DataConnectionStateListener,
561             TelephonyCallback.ServiceStateListener,
562             TelephonyCallback.DisplayInfoListener {
563         @Override
onDataConnectionStateChanged(int state, int networkType)564         public void onDataConnectionStateChanged(int state, int networkType) {
565             updateDataState(state);
566             updateNetworkType();
567         }
568 
569         @Override
onServiceStateChanged(ServiceState serviceState)570         public void onServiceStateChanged(ServiceState serviceState) {
571             updateNetworkProvider();
572             updateServiceState(serviceState);
573             updateRoamingStatus(serviceState);
574         }
575 
576         @Override
onDisplayInfoChanged(@onNull TelephonyDisplayInfo displayInfo)577         public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo displayInfo) {
578             mTelephonyDisplayInfo = displayInfo;
579             updateNetworkType();
580         }
581     }
582 
583     @VisibleForTesting
getNetworkTypeName(@nnotation.NetworkType int type)584     static String getNetworkTypeName(@Annotation.NetworkType int type) {
585         switch (type) {
586             case TelephonyManager.NETWORK_TYPE_GPRS:
587                 return "GPRS";
588             case TelephonyManager.NETWORK_TYPE_EDGE:
589                 return "EDGE";
590             case TelephonyManager.NETWORK_TYPE_UMTS:
591                 return "UMTS";
592             case TelephonyManager.NETWORK_TYPE_HSDPA:
593                 return "HSDPA";
594             case TelephonyManager.NETWORK_TYPE_HSUPA:
595                 return "HSUPA";
596             case TelephonyManager.NETWORK_TYPE_HSPA:
597                 return "HSPA";
598             case TelephonyManager.NETWORK_TYPE_CDMA:
599                 return "CDMA";
600             case TelephonyManager.NETWORK_TYPE_EVDO_0:
601                 return "CDMA - EvDo rev. 0";
602             case TelephonyManager.NETWORK_TYPE_EVDO_A:
603                 return "CDMA - EvDo rev. A";
604             case TelephonyManager.NETWORK_TYPE_EVDO_B:
605                 return "CDMA - EvDo rev. B";
606             case TelephonyManager.NETWORK_TYPE_1xRTT:
607                 return "CDMA - 1xRTT";
608             case TelephonyManager.NETWORK_TYPE_LTE:
609                 return "LTE";
610             case TelephonyManager.NETWORK_TYPE_EHRPD:
611                 return "CDMA - eHRPD";
612             case TelephonyManager.NETWORK_TYPE_IDEN:
613                 return "iDEN";
614             case TelephonyManager.NETWORK_TYPE_HSPAP:
615                 return "HSPA+";
616             case TelephonyManager.NETWORK_TYPE_GSM:
617                 return "GSM";
618             case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
619                 return "TD_SCDMA";
620             case TelephonyManager.NETWORK_TYPE_IWLAN:
621                 return "IWLAN";
622 //          case TelephonyManager.NETWORK_TYPE_LTE_CA:
623 //              return "LTE_CA";
624             case TelephonyManager.NETWORK_TYPE_NR:
625                 return "NR SA";
626             default:
627                 return "UNKNOWN";
628         }
629     }
630 }
631