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