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