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 128 public MyHandler(Status activity) { 129 mStatus = new WeakReference<Status>(activity); 130 } 131 132 @Override 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 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 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 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 */ 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 */ 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 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 332 private void updateNetworkType() { 333 // Whether EDGE, UMTS, etc... 334 setSummary(KEY_NETWORK_TYPE, TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, sUnknown); 335 } 336 337 private void updateDataState() { 338 int state = mTelephonyManager.getDataState(); 339 String display = mRes.getString(R.string.radioInfo_unknown); 340 341 switch (state) { 342 case TelephonyManager.DATA_CONNECTED: 343 display = mRes.getString(R.string.radioInfo_data_connected); 344 break; 345 case TelephonyManager.DATA_SUSPENDED: 346 display = mRes.getString(R.string.radioInfo_data_suspended); 347 break; 348 case TelephonyManager.DATA_CONNECTING: 349 display = mRes.getString(R.string.radioInfo_data_connecting); 350 break; 351 case TelephonyManager.DATA_DISCONNECTED: 352 display = mRes.getString(R.string.radioInfo_data_disconnected); 353 break; 354 } 355 356 setSummaryText(KEY_DATA_STATE, display); 357 } 358 359 private void updateServiceState(ServiceState serviceState) { 360 int state = serviceState.getState(); 361 String display = mRes.getString(R.string.radioInfo_unknown); 362 363 switch (state) { 364 case ServiceState.STATE_IN_SERVICE: 365 display = mRes.getString(R.string.radioInfo_service_in); 366 break; 367 case ServiceState.STATE_OUT_OF_SERVICE: 368 case ServiceState.STATE_EMERGENCY_ONLY: 369 display = mRes.getString(R.string.radioInfo_service_out); 370 break; 371 case ServiceState.STATE_POWER_OFF: 372 display = mRes.getString(R.string.radioInfo_service_off); 373 break; 374 } 375 376 setSummaryText(KEY_SERVICE_STATE, display); 377 378 if (serviceState.getRoaming()) { 379 setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_in)); 380 } else { 381 setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_not)); 382 } 383 setSummaryText(KEY_OPERATOR_NAME, serviceState.getOperatorAlphaLong()); 384 } 385 386 void updateSignalStrength() { 387 // TODO PhoneStateIntentReceiver is deprecated and PhoneStateListener 388 // should probably used instead. 389 390 // not loaded in some versions of the code (e.g., zaku) 391 if (mSignalStrength != null) { 392 int state = 393 mPhoneStateReceiver.getServiceState().getState(); 394 Resources r = getResources(); 395 396 if ((ServiceState.STATE_OUT_OF_SERVICE == state) || 397 (ServiceState.STATE_POWER_OFF == state)) { 398 mSignalStrength.setSummary("0"); 399 } 400 401 int signalDbm = mPhoneStateReceiver.getSignalStrengthDbm(); 402 403 if (-1 == signalDbm) signalDbm = 0; 404 405 int signalAsu = mPhoneStateReceiver.getSignalStrengthLevelAsu(); 406 407 if (-1 == signalAsu) signalAsu = 0; 408 409 mSignalStrength.setSummary(String.valueOf(signalDbm) + " " 410 + r.getString(R.string.radioInfo_display_dbm) + " " 411 + String.valueOf(signalAsu) + " " 412 + r.getString(R.string.radioInfo_display_asu)); 413 } 414 } 415 416 private void setWimaxStatus() { 417 ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); 418 NetworkInfo ni = cm.getNetworkInfo(ConnectivityManager.TYPE_WIMAX); 419 420 if (ni == null) { 421 PreferenceScreen root = getPreferenceScreen(); 422 Preference ps = (Preference) findPreference(KEY_WIMAX_MAC_ADDRESS); 423 if (ps != null) root.removePreference(ps); 424 } else { 425 Preference wimaxMacAddressPref = findPreference(KEY_WIMAX_MAC_ADDRESS); 426 String macAddress = SystemProperties.get("net.wimax.mac.address", 427 getString(R.string.status_unavailable)); 428 wimaxMacAddressPref.setSummary(macAddress); 429 } 430 } 431 private void setWifiStatus() { 432 WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE); 433 WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 434 435 Preference wifiMacAddressPref = findPreference(KEY_WIFI_MAC_ADDRESS); 436 437 String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress(); 438 wifiMacAddressPref.setSummary(!TextUtils.isEmpty(macAddress) ? macAddress 439 : getString(R.string.status_unavailable)); 440 } 441 442 private void setIpAddressStatus() { 443 Preference ipAddressPref = findPreference(KEY_IP_ADDRESS); 444 String ipAddress = Utils.getDefaultIpAddresses(this); 445 if (ipAddress != null) { 446 ipAddressPref.setSummary(ipAddress); 447 } else { 448 ipAddressPref.setSummary(getString(R.string.status_unavailable)); 449 } 450 } 451 452 private void setBtStatus() { 453 BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter(); 454 Preference btAddressPref = findPreference(KEY_BT_ADDRESS); 455 456 if (bluetooth == null) { 457 // device not BT capable 458 getPreferenceScreen().removePreference(btAddressPref); 459 } else { 460 String address = bluetooth.isEnabled() ? bluetooth.getAddress() : null; 461 btAddressPref.setSummary(!TextUtils.isEmpty(address) ? address 462 : getString(R.string.status_unavailable)); 463 } 464 } 465 466 void updateTimes() { 467 long at = SystemClock.uptimeMillis() / 1000; 468 long ut = SystemClock.elapsedRealtime() / 1000; 469 470 if (ut == 0) { 471 ut = 1; 472 } 473 474 mUptime.setSummary(convert(ut)); 475 } 476 477 private String pad(int n) { 478 if (n >= 10) { 479 return String.valueOf(n); 480 } else { 481 return "0" + String.valueOf(n); 482 } 483 } 484 485 private String convert(long t) { 486 int s = (int)(t % 60); 487 int m = (int)((t / 60) % 60); 488 int h = (int)((t / 3600)); 489 490 return h + ":" + pad(m) + ":" + pad(s); 491 } 492 } 493