• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.pm.PackageManager.NameNotFoundException;
24 import android.content.res.Resources;
25 import android.os.Bundle;
26 import android.os.PersistableBundle;
27 import android.os.UserHandle;
28 import android.os.UserManager;
29 import android.support.v7.preference.Preference;
30 import android.telephony.CarrierConfigManager;
31 import android.telephony.CellBroadcastMessage;
32 import android.telephony.PhoneStateListener;
33 import android.telephony.ServiceState;
34 import android.telephony.SignalStrength;
35 import android.telephony.SubscriptionInfo;
36 import android.telephony.SubscriptionManager;
37 import android.telephony.TelephonyManager;
38 import android.text.TextUtils;
39 import android.util.Log;
40 import android.view.LayoutInflater;
41 import android.view.View;
42 import android.view.ViewGroup;
43 import android.widget.ListView;
44 import android.widget.TabHost;
45 import android.widget.TabHost.OnTabChangeListener;
46 import android.widget.TabHost.TabContentFactory;
47 import android.widget.TabHost.TabSpec;
48 import android.widget.TabWidget;
49 
50 import com.android.internal.logging.MetricsProto.MetricsEvent;
51 import com.android.internal.telephony.DefaultPhoneNotifier;
52 import com.android.internal.telephony.Phone;
53 import com.android.internal.telephony.PhoneFactory;
54 import com.android.settings.R;
55 import com.android.settings.SettingsPreferenceFragment;
56 import com.android.settings.Utils;
57 import com.android.settingslib.DeviceInfoUtils;
58 
59 import java.util.List;
60 
61 import static android.content.Context.CARRIER_CONFIG_SERVICE;
62 import static android.content.Context.TELEPHONY_SERVICE;
63 
64 
65 /**
66  * Display the following information
67  * # Phone Number
68  * # Network
69  * # Roaming
70  * # Device Id (IMEI in GSM and MEID in CDMA)
71  * # Network type
72  * # Operator info (area info cell broadcast for Brazil)
73  * # Signal Strength
74  *
75  */
76 public class SimStatus extends SettingsPreferenceFragment {
77     private static final String TAG = "SimStatus";
78 
79     private static final String KEY_DATA_STATE = "data_state";
80     private static final String KEY_SERVICE_STATE = "service_state";
81     private static final String KEY_OPERATOR_NAME = "operator_name";
82     private static final String KEY_ROAMING_STATE = "roaming_state";
83     private static final String KEY_NETWORK_TYPE = "network_type";
84     private static final String KEY_LATEST_AREA_INFO = "latest_area_info";
85     private static final String KEY_PHONE_NUMBER = "number";
86     private static final String KEY_SIGNAL_STRENGTH = "signal_strength";
87     private static final String KEY_IMEI = "imei";
88     private static final String KEY_IMEI_SV = "imei_sv";
89     private static final String KEY_ICCID = "iccid";
90     private static final String COUNTRY_ABBREVIATION_BRAZIL = "br";
91 
92     static final String CB_AREA_INFO_RECEIVED_ACTION =
93             "android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED";
94 
95     static final String GET_LATEST_CB_AREA_INFO_ACTION =
96             "android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO";
97 
98     // Require the sender to have this permission to prevent third-party spoofing.
99     static final String CB_AREA_INFO_SENDER_PERMISSION =
100             "android.permission.RECEIVE_EMERGENCY_BROADCAST";
101 
102 
103     private TelephonyManager mTelephonyManager;
104     private CarrierConfigManager mCarrierConfigManager;
105     private Phone mPhone = null;
106     private Resources mRes;
107     private Preference mSignalStrength;
108     private SubscriptionInfo mSir;
109     private boolean mShowLatestAreaInfo;
110     private boolean mShowICCID;
111 
112     // Default summary for items
113     private String mDefaultText;
114 
115     private TabHost mTabHost;
116     private TabWidget mTabWidget;
117     private ListView mListView;
118     private List<SubscriptionInfo> mSelectableSubInfos;
119 
120     private PhoneStateListener mPhoneStateListener;
121     private BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() {
122         @Override
123         public void onReceive(Context context, Intent intent) {
124             String action = intent.getAction();
125             if (CB_AREA_INFO_RECEIVED_ACTION.equals(action)) {
126                 Bundle extras = intent.getExtras();
127                 if (extras == null) {
128                     return;
129                 }
130                 CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message");
131                 if (cbMessage != null && cbMessage.getServiceCategory() == 50
132                         && mSir.getSubscriptionId() == cbMessage.getSubId()) {
133                     String latestAreaInfo = cbMessage.getMessageBody();
134                     updateAreaInfo(latestAreaInfo);
135                 }
136             }
137         }
138     };
139 
140     @Override
onCreate(Bundle icicle)141     public void onCreate(Bundle icicle) {
142         super.onCreate(icicle);
143         mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
144         mCarrierConfigManager = (CarrierConfigManager) getSystemService(CARRIER_CONFIG_SERVICE);
145 
146         mSelectableSubInfos = SubscriptionManager.from(getContext())
147                 .getActiveSubscriptionInfoList();
148 
149         addPreferencesFromResource(R.xml.device_info_sim_status);
150 
151         mRes = getResources();
152         mDefaultText = mRes.getString(R.string.device_info_default);
153         // Note - missing in zaku build, be careful later...
154         mSignalStrength = findPreference(KEY_SIGNAL_STRENGTH);
155     }
156 
157     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)158     public View onCreateView(LayoutInflater inflater, ViewGroup container,
159             Bundle savedInstanceState) {
160         if (mSelectableSubInfos == null) {
161             mSir = null;
162         } else {
163             mSir = mSelectableSubInfos.size() > 0 ? mSelectableSubInfos.get(0) : null;
164 
165             if (mSelectableSubInfos.size() > 1) {
166                 View view = inflater.inflate(R.layout.icc_lock_tabs, container, false);
167                 final ViewGroup prefs_container = (ViewGroup) view.findViewById(
168                         R.id.prefs_container);
169                 Utils.prepareCustomPreferencesList(container, view, prefs_container, false);
170                 View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState);
171                 prefs_container.addView(prefs);
172 
173                 mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
174                 mTabWidget = (TabWidget) view.findViewById(android.R.id.tabs);
175                 mListView = (ListView) view.findViewById(android.R.id.list);
176 
177                 mTabHost.setup();
178                 mTabHost.setOnTabChangedListener(mTabListener);
179                 mTabHost.clearAllTabs();
180 
181                 for (int i = 0; i < mSelectableSubInfos.size(); i++) {
182                     mTabHost.addTab(buildTabSpec(String.valueOf(i),
183                             String.valueOf(mSelectableSubInfos.get(i).getDisplayName())));
184                 }
185                 return view;
186             }
187         }
188         return super.onCreateView(inflater, container, savedInstanceState);
189     }
190 
191     @Override
onViewCreated(View view, Bundle savedInstanceState)192     public void onViewCreated(View view, Bundle savedInstanceState) {
193         super.onViewCreated(view, savedInstanceState);
194 
195         updatePhoneInfos();
196     }
197 
198     @Override
getMetricsCategory()199     protected int getMetricsCategory() {
200         return MetricsEvent.DEVICEINFO_SIM_STATUS;
201     }
202 
203     @Override
onResume()204     public void onResume() {
205         super.onResume();
206         if (mPhone != null) {
207             updatePreference();
208 
209             updateSignalStrength(mPhone.getSignalStrength());
210             updateServiceState(mPhone.getServiceState());
211             updateDataState();
212             mTelephonyManager.listen(mPhoneStateListener,
213                     PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
214                     | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
215                     | PhoneStateListener.LISTEN_SERVICE_STATE);
216             if (mShowLatestAreaInfo) {
217                 getContext().registerReceiver(mAreaInfoReceiver,
218                         new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION),
219                         CB_AREA_INFO_SENDER_PERMISSION, null);
220                 // Ask CellBroadcastReceiver to broadcast the latest area info received
221                 Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION);
222                 getContext().sendBroadcastAsUser(getLatestIntent, UserHandle.ALL,
223                         CB_AREA_INFO_SENDER_PERMISSION);
224             }
225         }
226     }
227 
228     @Override
onPause()229     public void onPause() {
230         super.onPause();
231 
232         if (mPhone != null) {
233             mTelephonyManager.listen(mPhoneStateListener,
234                     PhoneStateListener.LISTEN_NONE);
235         }
236         if (mShowLatestAreaInfo) {
237             getContext().unregisterReceiver(mAreaInfoReceiver);
238         }
239     }
240 
241     /**
242      * Removes the specified preference, if it exists.
243      * @param key the key for the Preference item
244      */
removePreferenceFromScreen(String key)245     private void removePreferenceFromScreen(String key) {
246         Preference pref = findPreference(key);
247         if (pref != null) {
248             getPreferenceScreen().removePreference(pref);
249         }
250     }
251 
setSummaryText(String key, String text)252     private void setSummaryText(String key, String text) {
253         if (TextUtils.isEmpty(text)) {
254             text = mDefaultText;
255         }
256         // some preferences may be missing
257         final Preference preference = findPreference(key);
258         if (preference != null) {
259             preference.setSummary(text);
260         }
261     }
262 
updateNetworkType()263     private void updateNetworkType() {
264         // Whether EDGE, UMTS, etc...
265         String networktype = null;
266         final int subId = mSir.getSubscriptionId();
267         final int actualDataNetworkType = mTelephonyManager.getDataNetworkType(
268                 mSir.getSubscriptionId());
269         final int actualVoiceNetworkType = mTelephonyManager.getVoiceNetworkType(
270                 mSir.getSubscriptionId());
271         if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) {
272             networktype = mTelephonyManager.getNetworkTypeName(actualDataNetworkType);
273         } else if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) {
274             networktype = mTelephonyManager.getNetworkTypeName(actualVoiceNetworkType);
275         }
276 
277         boolean show4GForLTE = false;
278         try {
279             Context con = getActivity().createPackageContext("com.android.systemui", 0);
280             int id = con.getResources().getIdentifier("config_show4GForLTE",
281                     "bool", "com.android.systemui");
282             show4GForLTE = con.getResources().getBoolean(id);
283         } catch (NameNotFoundException e) {
284             Log.e(TAG, "NameNotFoundException for show4GFotLTE");
285         }
286 
287         if (networktype != null && networktype.equals("LTE") && show4GForLTE) {
288             networktype = "4G";
289         }
290         setSummaryText(KEY_NETWORK_TYPE, networktype);
291     }
292 
updateDataState()293     private void updateDataState() {
294         final int state =
295                 DefaultPhoneNotifier.convertDataState(mPhone.getDataConnectionState());
296 
297         String display = mRes.getString(R.string.radioInfo_unknown);
298 
299         switch (state) {
300             case TelephonyManager.DATA_CONNECTED:
301                 display = mRes.getString(R.string.radioInfo_data_connected);
302                 break;
303             case TelephonyManager.DATA_SUSPENDED:
304                 display = mRes.getString(R.string.radioInfo_data_suspended);
305                 break;
306             case TelephonyManager.DATA_CONNECTING:
307                 display = mRes.getString(R.string.radioInfo_data_connecting);
308                 break;
309             case TelephonyManager.DATA_DISCONNECTED:
310                 display = mRes.getString(R.string.radioInfo_data_disconnected);
311                 break;
312         }
313 
314         setSummaryText(KEY_DATA_STATE, display);
315     }
316 
updateServiceState(ServiceState serviceState)317     private void updateServiceState(ServiceState serviceState) {
318         final int state = serviceState.getState();
319         String display = mRes.getString(R.string.radioInfo_unknown);
320 
321         switch (state) {
322             case ServiceState.STATE_IN_SERVICE:
323                 display = mRes.getString(R.string.radioInfo_service_in);
324                 break;
325             case ServiceState.STATE_OUT_OF_SERVICE:
326                 // Set signal strength to 0 when service state is STATE_OUT_OF_SERVICE
327                 mSignalStrength.setSummary("0");
328             case ServiceState.STATE_EMERGENCY_ONLY:
329                 // Set summary string of service state to radioInfo_service_out when
330                 // service state is both STATE_OUT_OF_SERVICE & STATE_EMERGENCY_ONLY
331                 display = mRes.getString(R.string.radioInfo_service_out);
332                 break;
333             case ServiceState.STATE_POWER_OFF:
334                 display = mRes.getString(R.string.radioInfo_service_off);
335                 // Also set signal strength to 0
336                 mSignalStrength.setSummary("0");
337                 break;
338         }
339 
340         setSummaryText(KEY_SERVICE_STATE, display);
341 
342         if (serviceState.getRoaming()) {
343             setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_in));
344         } else {
345             setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_not));
346         }
347         setSummaryText(KEY_OPERATOR_NAME, serviceState.getOperatorAlphaLong());
348     }
349 
updateAreaInfo(String areaInfo)350     private void updateAreaInfo(String areaInfo) {
351         if (areaInfo != null) {
352             setSummaryText(KEY_LATEST_AREA_INFO, areaInfo);
353         }
354     }
355 
updateSignalStrength(SignalStrength signalStrength)356     void updateSignalStrength(SignalStrength signalStrength) {
357         if (mSignalStrength != null) {
358             final int state = mPhone.getServiceState().getState();
359             Resources r = getResources();
360 
361             if ((ServiceState.STATE_OUT_OF_SERVICE == state) ||
362                     (ServiceState.STATE_POWER_OFF == state)) {
363                 mSignalStrength.setSummary("0");
364                 return;
365             }
366 
367             int signalDbm = signalStrength.getDbm();
368             int signalAsu = signalStrength.getAsuLevel();
369 
370             if (-1 == signalDbm) {
371                 signalDbm = 0;
372             }
373 
374             if (-1 == signalAsu) {
375                 signalAsu = 0;
376             }
377 
378             mSignalStrength.setSummary(r.getString(R.string.sim_signal_strength,
379                         signalDbm, signalAsu));
380         }
381     }
382 
updatePreference()383     private void updatePreference() {
384         if (mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) {
385             // only show area info when SIM country is Brazil
386             if (COUNTRY_ABBREVIATION_BRAZIL.equals(mTelephonyManager.getSimCountryIso(
387                             mSir.getSubscriptionId()))) {
388                 mShowLatestAreaInfo = true;
389             }
390         }
391         PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(
392                 mSir.getSubscriptionId());
393         mShowICCID = carrierConfig.getBoolean(
394                 CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL);
395 
396 
397         // If formattedNumber is null or empty, it'll display as "Unknown".
398         setSummaryText(KEY_PHONE_NUMBER,
399                 DeviceInfoUtils.getFormattedPhoneNumber(getContext(), mSir));
400         setSummaryText(KEY_IMEI, mPhone.getImei());
401         setSummaryText(KEY_IMEI_SV, mPhone.getDeviceSvn());
402 
403         if (!mShowICCID) {
404             removePreferenceFromScreen(KEY_ICCID);
405         } else {
406             // Get ICCID, which is SIM serial number
407             String iccid = mTelephonyManager.getSimSerialNumber(mSir.getSubscriptionId());
408             setSummaryText(KEY_ICCID, iccid);
409         }
410 
411         if (!mShowLatestAreaInfo) {
412             removePreferenceFromScreen(KEY_LATEST_AREA_INFO);
413         }
414     }
415 
updatePhoneInfos()416     private void updatePhoneInfos() {
417         if (mSir != null) {
418             // TODO: http://b/23763013
419             final Phone phone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId(
420                         mSir.getSubscriptionId()));
421             if (UserManager.get(getContext()).isAdminUser()
422                     && SubscriptionManager.isValidSubscriptionId(mSir.getSubscriptionId())) {
423                 if (phone == null) {
424                     Log.e(TAG, "Unable to locate a phone object for the given Subscription ID.");
425                     return;
426                 }
427 
428                 mPhone = phone;
429                 mPhoneStateListener = new PhoneStateListener(mSir.getSubscriptionId()) {
430                     @Override
431                     public void onDataConnectionStateChanged(int state) {
432                         updateDataState();
433                         updateNetworkType();
434                     }
435 
436                     @Override
437                     public void onSignalStrengthsChanged(SignalStrength signalStrength) {
438                         updateSignalStrength(signalStrength);
439                     }
440 
441                     @Override
442                     public void onServiceStateChanged(ServiceState serviceState) {
443                         updateServiceState(serviceState);
444                     }
445                 };
446             }
447         }
448     }
449     private OnTabChangeListener mTabListener = new OnTabChangeListener() {
450         @Override
451         public void onTabChanged(String tabId) {
452             final int slotId = Integer.parseInt(tabId);
453             mSir = mSelectableSubInfos.get(slotId);
454 
455             // The User has changed tab; update the SIM information.
456             updatePhoneInfos();
457             mTelephonyManager.listen(mPhoneStateListener,
458                     PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
459                     | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
460                     | PhoneStateListener.LISTEN_SERVICE_STATE);
461             updateDataState();
462             updateNetworkType();
463             updatePreference();
464         }
465     };
466 
467     private TabContentFactory mEmptyTabContent = new TabContentFactory() {
468         @Override
469         public View createTabContent(String tag) {
470             return new View(mTabHost.getContext());
471         }
472     };
473 
buildTabSpec(String tag, String title)474     private TabSpec buildTabSpec(String tag, String title) {
475         return mTabHost.newTabSpec(tag).setIndicator(title).setContent(
476                 mEmptyTabContent);
477     }
478 }
479