• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.content.Context.CARRIER_CONFIG_SERVICE;
20 import static android.content.Context.EUICC_SERVICE;
21 import static android.content.Context.TELEPHONY_SERVICE;
22 import static android.content.Context.TELEPHONY_SUBSCRIPTION_SERVICE;
23 
24 import android.Manifest;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.res.Resources;
30 import android.os.Bundle;
31 import android.os.PersistableBundle;
32 import android.os.UserHandle;
33 import android.telephony.CarrierConfigManager;
34 import android.telephony.CellBroadcastMessage;
35 import android.telephony.PhoneStateListener;
36 import android.telephony.ServiceState;
37 import android.telephony.SignalStrength;
38 import android.telephony.SubscriptionInfo;
39 import android.telephony.SubscriptionManager;
40 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
41 import android.telephony.TelephonyManager;
42 import android.telephony.euicc.EuiccManager;
43 import android.text.BidiFormatter;
44 import android.text.TextDirectionHeuristics;
45 import android.text.TextUtils;
46 
47 import androidx.annotation.NonNull;
48 import androidx.annotation.VisibleForTesting;
49 
50 import com.android.settings.R;
51 import com.android.settingslib.DeviceInfoUtils;
52 import com.android.settingslib.Utils;
53 import com.android.settingslib.core.lifecycle.Lifecycle;
54 import com.android.settingslib.core.lifecycle.LifecycleObserver;
55 import com.android.settingslib.core.lifecycle.events.OnPause;
56 import com.android.settingslib.core.lifecycle.events.OnResume;
57 
58 public class SimStatusDialogController implements LifecycleObserver, OnResume, OnPause {
59 
60     private final static String TAG = "SimStatusDialogCtrl";
61 
62     @VisibleForTesting
63     final static int NETWORK_PROVIDER_VALUE_ID = R.id.operator_name_value;
64     @VisibleForTesting
65     final static int PHONE_NUMBER_VALUE_ID = R.id.number_value;
66     @VisibleForTesting
67     final static int CELLULAR_NETWORK_STATE = R.id.data_state_value;
68     @VisibleForTesting
69     final static int OPERATOR_INFO_LABEL_ID = R.id.latest_area_info_label;
70     @VisibleForTesting
71     final static int OPERATOR_INFO_VALUE_ID = R.id.latest_area_info_value;
72     @VisibleForTesting
73     final static int SERVICE_STATE_VALUE_ID = R.id.service_state_value;
74     @VisibleForTesting
75     final static int SIGNAL_STRENGTH_LABEL_ID = R.id.signal_strength_label;
76     @VisibleForTesting
77     final static int SIGNAL_STRENGTH_VALUE_ID = R.id.signal_strength_value;
78     @VisibleForTesting
79     final static int CELL_VOICE_NETWORK_TYPE_VALUE_ID = R.id.voice_network_type_value;
80     @VisibleForTesting
81     final static int CELL_DATA_NETWORK_TYPE_VALUE_ID = R.id.data_network_type_value;
82     @VisibleForTesting
83     final static int ROAMING_INFO_VALUE_ID = R.id.roaming_state_value;
84     @VisibleForTesting
85     final static int ICCID_INFO_LABEL_ID = R.id.icc_id_label;
86     @VisibleForTesting
87     final static int ICCID_INFO_VALUE_ID = R.id.icc_id_value;
88     @VisibleForTesting
89     final static int EID_INFO_VALUE_ID = R.id.esim_id_value;
90     @VisibleForTesting
91     final static int IMS_REGISTRATION_STATE_LABEL_ID = R.id.ims_reg_state_label;
92     @VisibleForTesting
93     final static int IMS_REGISTRATION_STATE_VALUE_ID = R.id.ims_reg_state_value;
94 
95     private final static String CB_AREA_INFO_RECEIVED_ACTION =
96             "com.android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED";
97     private final static String GET_LATEST_CB_AREA_INFO_ACTION =
98             "com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO";
99     private final static String CELL_BROADCAST_RECEIVER_APP = "com.android.cellbroadcastreceiver";
100 
101     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
102             new OnSubscriptionsChangedListener() {
103                 @Override
104                 public void onSubscriptionsChanged() {
105                     mSubscriptionInfo = mSubscriptionManager.getActiveSubscriptionInfo(
106                             mSubscriptionInfo.getSubscriptionId());
107                     updateNetworkProvider();
108                 }
109             };
110 
111     private SubscriptionInfo mSubscriptionInfo;
112 
113     private final SimStatusDialogFragment mDialog;
114     private final TelephonyManager mTelephonyManager;
115     private final SubscriptionManager mSubscriptionManager;
116     private final CarrierConfigManager mCarrierConfigManager;
117     private final EuiccManager mEuiccManager;
118     private final Resources mRes;
119     private final Context mContext;
120 
121     private boolean mShowLatestAreaInfo;
122 
123     private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() {
124         @Override
125         public void onReceive(Context context, Intent intent) {
126             final String action = intent.getAction();
127             if (TextUtils.equals(action, CB_AREA_INFO_RECEIVED_ACTION)) {
128                 final Bundle extras = intent.getExtras();
129                 if (extras == null) {
130                     return;
131                 }
132                 final CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message");
133                 if (cbMessage != null
134                         && mSubscriptionInfo.getSubscriptionId() == cbMessage.getSubId()) {
135                     final String latestAreaInfo = cbMessage.getMessageBody();
136                     mDialog.setText(OPERATOR_INFO_VALUE_ID, latestAreaInfo);
137                 }
138             }
139         }
140     };
141 
142     private PhoneStateListener mPhoneStateListener;
143 
SimStatusDialogController(@onNull SimStatusDialogFragment dialog, Lifecycle lifecycle, int slotId)144     public SimStatusDialogController(@NonNull SimStatusDialogFragment dialog, Lifecycle lifecycle,
145             int slotId) {
146         mDialog = dialog;
147         mContext = dialog.getContext();
148         mSubscriptionInfo = getPhoneSubscriptionInfo(slotId);
149         mTelephonyManager =  mContext.getSystemService(TelephonyManager.class);
150         mCarrierConfigManager =  mContext.getSystemService(CarrierConfigManager.class);
151         mEuiccManager =  mContext.getSystemService(EuiccManager.class);
152         mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
153 
154         mRes = mContext.getResources();
155 
156         if (lifecycle != null) {
157             lifecycle.addObserver(this);
158         }
159     }
160 
initialize()161     public void initialize() {
162         updateEid();
163 
164         if (mSubscriptionInfo == null) {
165             return;
166         }
167 
168         mPhoneStateListener = getPhoneStateListener();
169         updateNetworkProvider();
170 
171         final ServiceState serviceState = getCurrentServiceState();
172         updatePhoneNumber();
173         updateLatestAreaInfo();
174         updateServiceState(serviceState);
175         updateSignalStrength(getSignalStrength());
176         updateNetworkType();
177         updateRoamingStatus(serviceState);
178         updateIccidNumber();
179         updateImsRegistrationState();
180     }
181 
182     @Override
onResume()183     public void onResume() {
184         if (mSubscriptionInfo == null) {
185             return;
186         }
187 
188         mTelephonyManager.createForSubscriptionId(mSubscriptionInfo.getSubscriptionId())
189                 .listen(mPhoneStateListener,
190                 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
191                         | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
192                         | PhoneStateListener.LISTEN_SERVICE_STATE);
193         mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
194 
195         if (mShowLatestAreaInfo) {
196             mContext.registerReceiver(mAreaInfoReceiver,
197                     new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION),
198                     Manifest.permission.RECEIVE_EMERGENCY_BROADCAST, null /* scheduler */);
199             // Ask CellBroadcastReceiver to broadcast the latest area info received
200             final Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION);
201             getLatestIntent.setPackage(CELL_BROADCAST_RECEIVER_APP);
202             mContext.sendBroadcastAsUser(getLatestIntent, UserHandle.ALL,
203                     Manifest.permission.RECEIVE_EMERGENCY_BROADCAST);
204         }
205     }
206 
207     @Override
onPause()208     public void onPause() {
209         if (mSubscriptionInfo == null) {
210             return;
211         }
212 
213         mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
214         mTelephonyManager.createForSubscriptionId(mSubscriptionInfo.getSubscriptionId())
215                 .listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
216 
217         if (mShowLatestAreaInfo) {
218             mContext.unregisterReceiver(mAreaInfoReceiver);
219         }
220     }
221 
updateNetworkProvider()222     private void updateNetworkProvider() {
223         final CharSequence carrierName =
224                 mSubscriptionInfo != null ? mSubscriptionInfo.getCarrierName() : null;
225         mDialog.setText(NETWORK_PROVIDER_VALUE_ID, carrierName);
226     }
227 
updatePhoneNumber()228     private void updatePhoneNumber() {
229         // If formattedNumber is null or empty, it'll display as "Unknown".
230         mDialog.setText(PHONE_NUMBER_VALUE_ID, BidiFormatter.getInstance().unicodeWrap(
231                 getPhoneNumber(), TextDirectionHeuristics.LTR));
232     }
233 
updateDataState(int state)234     private void updateDataState(int state) {
235         String networkStateValue;
236 
237         switch (state) {
238             case TelephonyManager.DATA_CONNECTED:
239                 networkStateValue = mRes.getString(R.string.radioInfo_data_connected);
240                 break;
241             case TelephonyManager.DATA_SUSPENDED:
242                 networkStateValue = mRes.getString(R.string.radioInfo_data_suspended);
243                 break;
244             case TelephonyManager.DATA_CONNECTING:
245                 networkStateValue = mRes.getString(R.string.radioInfo_data_connecting);
246                 break;
247             case TelephonyManager.DATA_DISCONNECTED:
248                 networkStateValue = mRes.getString(R.string.radioInfo_data_disconnected);
249                 break;
250             default:
251                 networkStateValue = mRes.getString(R.string.radioInfo_unknown);
252                 break;
253         }
254 
255         mDialog.setText(CELLULAR_NETWORK_STATE, networkStateValue);
256     }
257 
258 
updateLatestAreaInfo()259     private void updateLatestAreaInfo() {
260         mShowLatestAreaInfo = Resources.getSystem().getBoolean(
261                 com.android.internal.R.bool.config_showAreaUpdateInfoSettings)
262                 && mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA;
263 
264         if (!mShowLatestAreaInfo) {
265             mDialog.removeSettingFromScreen(OPERATOR_INFO_LABEL_ID);
266             mDialog.removeSettingFromScreen(OPERATOR_INFO_VALUE_ID);
267         }
268     }
269 
updateServiceState(ServiceState serviceState)270     private void updateServiceState(ServiceState serviceState) {
271         final int state = Utils.getCombinedServiceState(serviceState);
272         if (!Utils.isInService(serviceState)) {
273             resetSignalStrength();
274         }
275 
276         String serviceStateValue;
277 
278         switch (state) {
279             case ServiceState.STATE_IN_SERVICE:
280                 serviceStateValue = mRes.getString(R.string.radioInfo_service_in);
281                 break;
282             case ServiceState.STATE_OUT_OF_SERVICE:
283             case ServiceState.STATE_EMERGENCY_ONLY:
284                 // Set summary string of service state to radioInfo_service_out when
285                 // service state is both STATE_OUT_OF_SERVICE & STATE_EMERGENCY_ONLY
286                 serviceStateValue = mRes.getString(R.string.radioInfo_service_out);
287                 break;
288             case ServiceState.STATE_POWER_OFF:
289                 serviceStateValue = mRes.getString(R.string.radioInfo_service_off);
290                 break;
291             default:
292                 serviceStateValue = mRes.getString(R.string.radioInfo_unknown);
293                 break;
294         }
295 
296         mDialog.setText(SERVICE_STATE_VALUE_ID, serviceStateValue);
297     }
298 
updateSignalStrength(SignalStrength signalStrength)299     private void updateSignalStrength(SignalStrength signalStrength) {
300         if (signalStrength == null) {
301             return;
302         }
303         final int subscriptionId = mSubscriptionInfo.getSubscriptionId();
304         final PersistableBundle carrierConfig =
305                 mCarrierConfigManager.getConfigForSubId(subscriptionId);
306         // by default we show the signal strength
307         boolean showSignalStrength = true;
308         if (carrierConfig != null) {
309             showSignalStrength = carrierConfig.getBoolean(
310                     CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL);
311         }
312         if (!showSignalStrength) {
313             mDialog.removeSettingFromScreen(SIGNAL_STRENGTH_LABEL_ID);
314             mDialog.removeSettingFromScreen(SIGNAL_STRENGTH_VALUE_ID);
315             return;
316         }
317 
318         ServiceState serviceState = getCurrentServiceState();
319         if (serviceState == null || !Utils.isInService(serviceState)) {
320             return;
321         }
322 
323         int signalDbm = getDbm(signalStrength);
324         int signalAsu = getAsuLevel(signalStrength);
325 
326         if (signalDbm == -1) {
327             signalDbm = 0;
328         }
329 
330         if (signalAsu == -1) {
331             signalAsu = 0;
332         }
333 
334         mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, mRes.getString(R.string.sim_signal_strength,
335                 signalDbm, signalAsu));
336     }
337 
resetSignalStrength()338     private void resetSignalStrength() {
339         mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, "0");
340     }
341 
updateNetworkType()342     private void updateNetworkType() {
343         // Whether EDGE, UMTS, etc...
344         String dataNetworkTypeName = null;
345         String voiceNetworkTypeName = null;
346         final int subId = mSubscriptionInfo.getSubscriptionId();
347         final int actualDataNetworkType = mTelephonyManager.getDataNetworkType(subId);
348         final int actualVoiceNetworkType = mTelephonyManager.getVoiceNetworkType(subId);
349         if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) {
350             dataNetworkTypeName = mTelephonyManager.getNetworkTypeName(actualDataNetworkType);
351         }
352         if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) {
353             voiceNetworkTypeName = mTelephonyManager.getNetworkTypeName(actualVoiceNetworkType);
354         }
355 
356         boolean show4GForLTE = false;
357         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId);
358         if (carrierConfig != null) {
359             show4GForLTE = carrierConfig.getBoolean(
360                     CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
361         }
362 
363         if (show4GForLTE) {
364             if ("LTE".equals(dataNetworkTypeName)) {
365                 dataNetworkTypeName = "4G";
366             }
367             if ("LTE".equals(voiceNetworkTypeName)) {
368                 voiceNetworkTypeName = "4G";
369             }
370         }
371 
372         mDialog.setText(CELL_VOICE_NETWORK_TYPE_VALUE_ID, voiceNetworkTypeName);
373         mDialog.setText(CELL_DATA_NETWORK_TYPE_VALUE_ID, dataNetworkTypeName);
374     }
375 
updateRoamingStatus(ServiceState serviceState)376     private void updateRoamingStatus(ServiceState serviceState) {
377         if (serviceState.getRoaming()) {
378             mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_in));
379         } else {
380             mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_not));
381         }
382     }
383 
updateIccidNumber()384     private void updateIccidNumber() {
385         final int subscriptionId = mSubscriptionInfo.getSubscriptionId();
386         final PersistableBundle carrierConfig =
387                 mCarrierConfigManager.getConfigForSubId(subscriptionId);
388         // do not show iccid by default
389         boolean showIccId = false;
390         if (carrierConfig != null) {
391             showIccId = carrierConfig.getBoolean(
392                     CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL);
393         }
394         if (!showIccId) {
395             mDialog.removeSettingFromScreen(ICCID_INFO_LABEL_ID);
396             mDialog.removeSettingFromScreen(ICCID_INFO_VALUE_ID);
397         } else {
398             mDialog.setText(ICCID_INFO_VALUE_ID, getSimSerialNumber(subscriptionId));
399         }
400     }
401 
updateEid()402     private void updateEid() {
403         if (mEuiccManager.isEnabled()) {
404             mDialog.setText(EID_INFO_VALUE_ID, mEuiccManager.getEid());
405         } else {
406             mDialog.removeSettingFromScreen(EID_INFO_VALUE_ID);
407         }
408     }
409 
updateImsRegistrationState()410     private void updateImsRegistrationState() {
411         final int subscriptionId = mSubscriptionInfo.getSubscriptionId();
412         final PersistableBundle carrierConfig =
413             mCarrierConfigManager.getConfigForSubId(subscriptionId);
414         final boolean showImsRegState = carrierConfig == null ? false :
415             carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL);
416         if (showImsRegState) {
417             final boolean isImsRegistered = mTelephonyManager.isImsRegistered(subscriptionId);
418             mDialog.setText(IMS_REGISTRATION_STATE_VALUE_ID, mRes.getString(isImsRegistered ?
419                 R.string.ims_reg_status_registered : R.string.ims_reg_status_not_registered));
420         } else {
421             mDialog.removeSettingFromScreen(IMS_REGISTRATION_STATE_LABEL_ID);
422             mDialog.removeSettingFromScreen(IMS_REGISTRATION_STATE_VALUE_ID);
423         }
424     }
425 
getPhoneSubscriptionInfo(int slotId)426     private SubscriptionInfo getPhoneSubscriptionInfo(int slotId) {
427         return SubscriptionManager.from(mContext).getActiveSubscriptionInfoForSimSlotIndex(slotId);
428     }
429 
430     @VisibleForTesting
getCurrentServiceState()431     ServiceState getCurrentServiceState() {
432         return mTelephonyManager.getServiceStateForSubscriber(
433                 mSubscriptionInfo.getSubscriptionId());
434     }
435 
getDbm(SignalStrength signalStrength)436     private int getDbm(SignalStrength signalStrength) {
437         return signalStrength.getDbm();
438     }
439 
getAsuLevel(SignalStrength signalStrength)440     private int getAsuLevel(SignalStrength signalStrength) {
441         return signalStrength.getAsuLevel();
442     }
443 
444     @VisibleForTesting
getPhoneStateListener()445     PhoneStateListener getPhoneStateListener() {
446         return new PhoneStateListener() {
447             @Override
448             public void onDataConnectionStateChanged(int state) {
449                 updateDataState(state);
450                 updateNetworkType();
451             }
452 
453             @Override
454             public void onSignalStrengthsChanged(SignalStrength signalStrength) {
455                 updateSignalStrength(signalStrength);
456             }
457 
458             @Override
459             public void onServiceStateChanged(ServiceState serviceState) {
460                 updateNetworkProvider();
461                 updateServiceState(serviceState);
462                 updateRoamingStatus(serviceState);
463             }
464         };
465     }
466 
467     @VisibleForTesting
468     String getPhoneNumber() {
469         return DeviceInfoUtils.getFormattedPhoneNumber(mContext, mSubscriptionInfo);
470     }
471 
472     @VisibleForTesting
473     SignalStrength getSignalStrength() {
474         return mTelephonyManager.getSignalStrength();
475     }
476 
477     @VisibleForTesting
478     String getSimSerialNumber(int subscriptionId) {
479         return mTelephonyManager.getSimSerialNumber(subscriptionId);
480     }
481 }
482