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