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