1/* 2 * Copyright (C) 2008 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 17package com.android.settings.deviceinfo; 18 19import android.bluetooth.BluetoothAdapter; 20import android.content.BroadcastReceiver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.content.res.Resources; 25import android.net.ConnectivityManager; 26import android.net.NetworkInfo; 27import android.net.wifi.WifiInfo; 28import android.net.wifi.WifiManager; 29import android.os.Build; 30import android.os.Bundle; 31import android.os.Handler; 32import android.os.Message; 33import android.os.SystemClock; 34import android.os.SystemProperties; 35import android.os.UserHandle; 36import android.preference.Preference; 37import android.preference.PreferenceActivity; 38import android.preference.PreferenceScreen; 39import android.telephony.CellBroadcastMessage; 40import android.telephony.PhoneNumberUtils; 41import android.telephony.PhoneStateListener; 42import android.telephony.ServiceState; 43import android.telephony.TelephonyManager; 44import android.text.TextUtils; 45 46import com.android.internal.telephony.Phone; 47import com.android.internal.telephony.PhoneConstants; 48import com.android.internal.telephony.PhoneFactory; 49import com.android.internal.telephony.PhoneStateIntentReceiver; 50import com.android.settings.R; 51import com.android.settings.Utils; 52 53import java.lang.ref.WeakReference; 54 55/** 56 * Display the following information 57 * # Phone Number 58 * # Network 59 * # Roaming 60 * # Device Id (IMEI in GSM and MEID in CDMA) 61 * # Network type 62 * # Operator info (area info cell broadcast for Brazil) 63 * # Signal Strength 64 * # Battery Strength : TODO 65 * # Uptime 66 * # Awake Time 67 * # XMPP/buzz/tickle status : TODO 68 * 69 */ 70public class Status extends PreferenceActivity { 71 72 private static final String KEY_DATA_STATE = "data_state"; 73 private static final String KEY_SERVICE_STATE = "service_state"; 74 private static final String KEY_OPERATOR_NAME = "operator_name"; 75 private static final String KEY_ROAMING_STATE = "roaming_state"; 76 private static final String KEY_NETWORK_TYPE = "network_type"; 77 private static final String KEY_LATEST_AREA_INFO = "latest_area_info"; 78 private static final String KEY_PHONE_NUMBER = "number"; 79 private static final String KEY_IMEI_SV = "imei_sv"; 80 private static final String KEY_IMEI = "imei"; 81 private static final String KEY_PRL_VERSION = "prl_version"; 82 private static final String KEY_MIN_NUMBER = "min_number"; 83 private static final String KEY_MEID_NUMBER = "meid_number"; 84 private static final String KEY_SIGNAL_STRENGTH = "signal_strength"; 85 private static final String KEY_BATTERY_STATUS = "battery_status"; 86 private static final String KEY_BATTERY_LEVEL = "battery_level"; 87 private static final String KEY_IP_ADDRESS = "wifi_ip_address"; 88 private static final String KEY_WIFI_MAC_ADDRESS = "wifi_mac_address"; 89 private static final String KEY_BT_ADDRESS = "bt_address"; 90 private static final String KEY_SERIAL_NUMBER = "serial_number"; 91 private static final String KEY_ICC_ID = "icc_id"; 92 private static final String KEY_WIMAX_MAC_ADDRESS = "wimax_mac_address"; 93 private static final String[] PHONE_RELATED_ENTRIES = { 94 KEY_DATA_STATE, 95 KEY_SERVICE_STATE, 96 KEY_OPERATOR_NAME, 97 KEY_ROAMING_STATE, 98 KEY_NETWORK_TYPE, 99 KEY_LATEST_AREA_INFO, 100 KEY_PHONE_NUMBER, 101 KEY_IMEI, 102 KEY_IMEI_SV, 103 KEY_PRL_VERSION, 104 KEY_MIN_NUMBER, 105 KEY_MEID_NUMBER, 106 KEY_SIGNAL_STRENGTH, 107 KEY_ICC_ID 108 }; 109 110 static final String CB_AREA_INFO_RECEIVED_ACTION = 111 "android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED"; 112 113 static final String GET_LATEST_CB_AREA_INFO_ACTION = 114 "android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO"; 115 116 // Require the sender to have this permission to prevent third-party spoofing. 117 static final String CB_AREA_INFO_SENDER_PERMISSION = 118 "android.permission.RECEIVE_EMERGENCY_BROADCAST"; 119 120 private static final int EVENT_SIGNAL_STRENGTH_CHANGED = 200; 121 private static final int EVENT_SERVICE_STATE_CHANGED = 300; 122 123 private static final int EVENT_UPDATE_STATS = 500; 124 125 private TelephonyManager mTelephonyManager; 126 private Phone mPhone = null; 127 private PhoneStateIntentReceiver mPhoneStateReceiver; 128 private Resources mRes; 129 private Preference mSignalStrength; 130 private Preference mUptime; 131 private boolean mShowLatestAreaInfo; 132 133 private String sUnknown; 134 135 private Preference mBatteryStatus; 136 private Preference mBatteryLevel; 137 138 private Handler mHandler; 139 140 private static class MyHandler extends Handler { 141 private WeakReference<Status> mStatus; 142 143 public MyHandler(Status activity) { 144 mStatus = new WeakReference<Status>(activity); 145 } 146 147 @Override 148 public void handleMessage(Message msg) { 149 Status status = mStatus.get(); 150 if (status == null) { 151 return; 152 } 153 154 switch (msg.what) { 155 case EVENT_SIGNAL_STRENGTH_CHANGED: 156 status.updateSignalStrength(); 157 break; 158 159 case EVENT_SERVICE_STATE_CHANGED: 160 ServiceState serviceState = status.mPhoneStateReceiver.getServiceState(); 161 status.updateServiceState(serviceState); 162 break; 163 164 case EVENT_UPDATE_STATS: 165 status.updateTimes(); 166 sendEmptyMessageDelayed(EVENT_UPDATE_STATS, 1000); 167 break; 168 } 169 } 170 } 171 172 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() { 173 174 @Override 175 public void onReceive(Context context, Intent intent) { 176 String action = intent.getAction(); 177 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { 178 mBatteryLevel.setSummary(Utils.getBatteryPercentage(intent)); 179 mBatteryStatus.setSummary(Utils.getBatteryStatus(getResources(), intent)); 180 } 181 } 182 }; 183 184 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 185 @Override 186 public void onDataConnectionStateChanged(int state) { 187 updateDataState(); 188 updateNetworkType(); 189 } 190 }; 191 192 private BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() { 193 @Override 194 public void onReceive(Context context, Intent intent) { 195 String action = intent.getAction(); 196 if (CB_AREA_INFO_RECEIVED_ACTION.equals(action)) { 197 Bundle extras = intent.getExtras(); 198 if (extras == null) { 199 return; 200 } 201 CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message"); 202 if (cbMessage != null && cbMessage.getServiceCategory() == 50) { 203 String latestAreaInfo = cbMessage.getMessageBody(); 204 updateAreaInfo(latestAreaInfo); 205 } 206 } 207 } 208 }; 209 210 @Override 211 protected void onCreate(Bundle icicle) { 212 super.onCreate(icicle); 213 214 mHandler = new MyHandler(this); 215 216 mTelephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE); 217 218 addPreferencesFromResource(R.xml.device_info_status); 219 mBatteryLevel = findPreference(KEY_BATTERY_LEVEL); 220 mBatteryStatus = findPreference(KEY_BATTERY_STATUS); 221 222 mRes = getResources(); 223 sUnknown = mRes.getString(R.string.device_info_default); 224 if (UserHandle.myUserId() == UserHandle.USER_OWNER) { 225 mPhone = PhoneFactory.getDefaultPhone(); 226 } 227 // Note - missing in zaku build, be careful later... 228 mSignalStrength = findPreference(KEY_SIGNAL_STRENGTH); 229 mUptime = findPreference("up_time"); 230 231 if (mPhone == null || Utils.isWifiOnly(getApplicationContext())) { 232 for (String key : PHONE_RELATED_ENTRIES) { 233 removePreferenceFromScreen(key); 234 } 235 } else { 236 // NOTE "imei" is the "Device ID" since it represents 237 // the IMEI in GSM and the MEID in CDMA 238 if (mPhone.getPhoneName().equals("CDMA")) { 239 setSummaryText(KEY_MEID_NUMBER, mPhone.getMeid()); 240 setSummaryText(KEY_MIN_NUMBER, mPhone.getCdmaMin()); 241 if (getResources().getBoolean(R.bool.config_msid_enable)) { 242 findPreference(KEY_MIN_NUMBER).setTitle(R.string.status_msid_number); 243 } 244 setSummaryText(KEY_PRL_VERSION, mPhone.getCdmaPrlVersion()); 245 removePreferenceFromScreen(KEY_IMEI_SV); 246 247 if (mPhone.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) { 248 // Show ICC ID and IMEI for LTE device 249 setSummaryText(KEY_ICC_ID, mPhone.getIccSerialNumber()); 250 setSummaryText(KEY_IMEI, mPhone.getImei()); 251 } else { 252 // device is not GSM/UMTS, do not display GSM/UMTS features 253 // check Null in case no specified preference in overlay xml 254 removePreferenceFromScreen(KEY_IMEI); 255 removePreferenceFromScreen(KEY_ICC_ID); 256 } 257 } else { 258 setSummaryText(KEY_IMEI, mPhone.getDeviceId()); 259 260 setSummaryText(KEY_IMEI_SV, 261 ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)) 262 .getDeviceSoftwareVersion()); 263 264 // device is not CDMA, do not display CDMA features 265 // check Null in case no specified preference in overlay xml 266 removePreferenceFromScreen(KEY_PRL_VERSION); 267 removePreferenceFromScreen(KEY_MEID_NUMBER); 268 removePreferenceFromScreen(KEY_MIN_NUMBER); 269 removePreferenceFromScreen(KEY_ICC_ID); 270 271 // only show area info when SIM country is Brazil 272 if ("br".equals(mTelephonyManager.getSimCountryIso())) { 273 mShowLatestAreaInfo = true; 274 } 275 } 276 277 String rawNumber = mPhone.getLine1Number(); // may be null or empty 278 String formattedNumber = null; 279 if (!TextUtils.isEmpty(rawNumber)) { 280 formattedNumber = PhoneNumberUtils.formatNumber(rawNumber); 281 } 282 // If formattedNumber is null or empty, it'll display as "Unknown". 283 setSummaryText(KEY_PHONE_NUMBER, formattedNumber); 284 285 mPhoneStateReceiver = new PhoneStateIntentReceiver(this, mHandler); 286 mPhoneStateReceiver.notifySignalStrength(EVENT_SIGNAL_STRENGTH_CHANGED); 287 mPhoneStateReceiver.notifyServiceState(EVENT_SERVICE_STATE_CHANGED); 288 289 if (!mShowLatestAreaInfo) { 290 removePreferenceFromScreen(KEY_LATEST_AREA_INFO); 291 } 292 } 293 294 setWimaxStatus(); 295 setWifiStatus(); 296 setBtStatus(); 297 setIpAddressStatus(); 298 299 String serial = Build.SERIAL; 300 if (serial != null && !serial.equals("")) { 301 setSummaryText(KEY_SERIAL_NUMBER, serial); 302 } else { 303 removePreferenceFromScreen(KEY_SERIAL_NUMBER); 304 } 305 } 306 307 @Override 308 protected void onResume() { 309 super.onResume(); 310 311 if (mPhone != null && !Utils.isWifiOnly(getApplicationContext())) { 312 mPhoneStateReceiver.registerIntent(); 313 314 updateSignalStrength(); 315 updateServiceState(mPhone.getServiceState()); 316 updateDataState(); 317 mTelephonyManager.listen(mPhoneStateListener, 318 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE); 319 if (mShowLatestAreaInfo) { 320 registerReceiver(mAreaInfoReceiver, new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION), 321 CB_AREA_INFO_SENDER_PERMISSION, null); 322 // Ask CellBroadcastReceiver to broadcast the latest area info received 323 Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION); 324 sendBroadcastAsUser(getLatestIntent, UserHandle.ALL, 325 CB_AREA_INFO_SENDER_PERMISSION); 326 } 327 } 328 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 329 mHandler.sendEmptyMessage(EVENT_UPDATE_STATS); 330 } 331 332 @Override 333 public void onPause() { 334 super.onPause(); 335 336 if (mPhone != null && !Utils.isWifiOnly(getApplicationContext())) { 337 mPhoneStateReceiver.unregisterIntent(); 338 mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); 339 } 340 if (mShowLatestAreaInfo) { 341 unregisterReceiver(mAreaInfoReceiver); 342 } 343 unregisterReceiver(mBatteryInfoReceiver); 344 mHandler.removeMessages(EVENT_UPDATE_STATS); 345 } 346 347 /** 348 * Removes the specified preference, if it exists. 349 * @param key the key for the Preference item 350 */ 351 private void removePreferenceFromScreen(String key) { 352 Preference pref = findPreference(key); 353 if (pref != null) { 354 getPreferenceScreen().removePreference(pref); 355 } 356 } 357 358 /** 359 * @param preference The key for the Preference item 360 * @param property The system property to fetch 361 * @param alt The default value, if the property doesn't exist 362 */ 363 private void setSummary(String preference, String property, String alt) { 364 try { 365 findPreference(preference).setSummary( 366 SystemProperties.get(property, alt)); 367 } catch (RuntimeException e) { 368 369 } 370 } 371 372 private void setSummaryText(String preference, String text) { 373 if (TextUtils.isEmpty(text)) { 374 text = sUnknown; 375 } 376 // some preferences may be missing 377 if (findPreference(preference) != null) { 378 findPreference(preference).setSummary(text); 379 } 380 } 381 382 private void updateNetworkType() { 383 // Whether EDGE, UMTS, etc... 384 String networktype = null; 385 if (TelephonyManager.NETWORK_TYPE_UNKNOWN != mTelephonyManager.getNetworkType()) { 386 networktype = mTelephonyManager.getNetworkTypeName(); 387 } 388 setSummaryText(KEY_NETWORK_TYPE, networktype); 389 } 390 391 private void updateDataState() { 392 int state = mTelephonyManager.getDataState(); 393 String display = mRes.getString(R.string.radioInfo_unknown); 394 395 switch (state) { 396 case TelephonyManager.DATA_CONNECTED: 397 display = mRes.getString(R.string.radioInfo_data_connected); 398 break; 399 case TelephonyManager.DATA_SUSPENDED: 400 display = mRes.getString(R.string.radioInfo_data_suspended); 401 break; 402 case TelephonyManager.DATA_CONNECTING: 403 display = mRes.getString(R.string.radioInfo_data_connecting); 404 break; 405 case TelephonyManager.DATA_DISCONNECTED: 406 display = mRes.getString(R.string.radioInfo_data_disconnected); 407 break; 408 } 409 410 setSummaryText(KEY_DATA_STATE, display); 411 } 412 413 private void updateServiceState(ServiceState serviceState) { 414 int state = serviceState.getState(); 415 String display = mRes.getString(R.string.radioInfo_unknown); 416 417 switch (state) { 418 case ServiceState.STATE_IN_SERVICE: 419 display = mRes.getString(R.string.radioInfo_service_in); 420 break; 421 case ServiceState.STATE_OUT_OF_SERVICE: 422 case ServiceState.STATE_EMERGENCY_ONLY: 423 display = mRes.getString(R.string.radioInfo_service_out); 424 break; 425 case ServiceState.STATE_POWER_OFF: 426 display = mRes.getString(R.string.radioInfo_service_off); 427 break; 428 } 429 430 setSummaryText(KEY_SERVICE_STATE, display); 431 432 if (serviceState.getRoaming()) { 433 setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_in)); 434 } else { 435 setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_not)); 436 } 437 setSummaryText(KEY_OPERATOR_NAME, serviceState.getOperatorAlphaLong()); 438 } 439 440 private void updateAreaInfo(String areaInfo) { 441 if (areaInfo != null) { 442 setSummaryText(KEY_LATEST_AREA_INFO, areaInfo); 443 } 444 } 445 446 void updateSignalStrength() { 447 // TODO PhoneStateIntentReceiver is deprecated and PhoneStateListener 448 // should probably used instead. 449 450 // not loaded in some versions of the code (e.g., zaku) 451 if (mSignalStrength != null) { 452 int state = 453 mPhoneStateReceiver.getServiceState().getState(); 454 Resources r = getResources(); 455 456 if ((ServiceState.STATE_OUT_OF_SERVICE == state) || 457 (ServiceState.STATE_POWER_OFF == state)) { 458 mSignalStrength.setSummary("0"); 459 } 460 461 int signalDbm = mPhoneStateReceiver.getSignalStrengthDbm(); 462 463 if (-1 == signalDbm) signalDbm = 0; 464 465 int signalAsu = mPhoneStateReceiver.getSignalStrengthLevelAsu(); 466 467 if (-1 == signalAsu) signalAsu = 0; 468 469 mSignalStrength.setSummary(String.valueOf(signalDbm) + " " 470 + r.getString(R.string.radioInfo_display_dbm) + " " 471 + String.valueOf(signalAsu) + " " 472 + r.getString(R.string.radioInfo_display_asu)); 473 } 474 } 475 476 private void setWimaxStatus() { 477 ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); 478 NetworkInfo ni = cm.getNetworkInfo(ConnectivityManager.TYPE_WIMAX); 479 480 if (ni == null) { 481 PreferenceScreen root = getPreferenceScreen(); 482 Preference ps = (Preference) findPreference(KEY_WIMAX_MAC_ADDRESS); 483 if (ps != null) root.removePreference(ps); 484 } else { 485 Preference wimaxMacAddressPref = findPreference(KEY_WIMAX_MAC_ADDRESS); 486 String macAddress = SystemProperties.get("net.wimax.mac.address", 487 getString(R.string.status_unavailable)); 488 wimaxMacAddressPref.setSummary(macAddress); 489 } 490 } 491 private void setWifiStatus() { 492 WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE); 493 WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 494 495 Preference wifiMacAddressPref = findPreference(KEY_WIFI_MAC_ADDRESS); 496 497 String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress(); 498 wifiMacAddressPref.setSummary(!TextUtils.isEmpty(macAddress) ? macAddress 499 : getString(R.string.status_unavailable)); 500 } 501 502 private void setIpAddressStatus() { 503 Preference ipAddressPref = findPreference(KEY_IP_ADDRESS); 504 String ipAddress = Utils.getDefaultIpAddresses(this); 505 if (ipAddress != null) { 506 ipAddressPref.setSummary(ipAddress); 507 } else { 508 ipAddressPref.setSummary(getString(R.string.status_unavailable)); 509 } 510 } 511 512 private void setBtStatus() { 513 BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter(); 514 Preference btAddressPref = findPreference(KEY_BT_ADDRESS); 515 516 if (bluetooth == null) { 517 // device not BT capable 518 getPreferenceScreen().removePreference(btAddressPref); 519 } else { 520 String address = bluetooth.isEnabled() ? bluetooth.getAddress() : null; 521 btAddressPref.setSummary(!TextUtils.isEmpty(address) ? address 522 : getString(R.string.status_unavailable)); 523 } 524 } 525 526 void updateTimes() { 527 long at = SystemClock.uptimeMillis() / 1000; 528 long ut = SystemClock.elapsedRealtime() / 1000; 529 530 if (ut == 0) { 531 ut = 1; 532 } 533 534 mUptime.setSummary(convert(ut)); 535 } 536 537 private String pad(int n) { 538 if (n >= 10) { 539 return String.valueOf(n); 540 } else { 541 return "0" + String.valueOf(n); 542 } 543 } 544 545 private String convert(long t) { 546 int s = (int)(t % 60); 547 int m = (int)((t / 60) % 60); 548 int h = (int)((t / 3600)); 549 550 return h + ":" + pad(m) + ":" + pad(s); 551 } 552} 553