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