NetworkController.java revision acab04dfc16f0ad08ecd167ae759c158cea2e19f
1/* 2 * Copyright (C) 2010 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.systemui.statusbar.policy; 18 19import java.io.FileDescriptor; 20import java.io.PrintWriter; 21import java.util.ArrayList; 22import java.util.List; 23 24import android.content.BroadcastReceiver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.content.res.Resources; 29import android.net.ConnectivityManager; 30import android.net.NetworkInfo; 31import android.net.wifi.SupplicantState; 32import android.net.wifi.WifiConfiguration; 33import android.net.wifi.WifiInfo; 34import android.net.wifi.WifiManager; 35import android.os.Binder; 36import android.os.Handler; 37import android.os.HandlerThread; 38import android.os.Looper; 39import android.os.Message; 40import android.os.Messenger; 41import android.os.RemoteException; 42import android.os.SystemProperties; 43import android.provider.Settings; 44import android.provider.Telephony; 45import android.telephony.PhoneStateListener; 46import android.telephony.ServiceState; 47import android.telephony.SignalStrength; 48import android.telephony.TelephonyManager; 49import android.util.Slog; 50import android.view.View; 51import android.widget.ImageView; 52import android.widget.TextView; 53 54import com.android.internal.app.IBatteryStats; 55import com.android.internal.telephony.IccCard; 56import com.android.internal.telephony.TelephonyIntents; 57import com.android.internal.telephony.cdma.EriInfo; 58import com.android.server.am.BatteryStatsService; 59import com.android.internal.util.AsyncChannel; 60 61import com.android.systemui.R; 62 63public class NetworkController extends BroadcastReceiver { 64 // debug 65 static final String TAG = "StatusBar.NetworkController"; 66 static final boolean DEBUG = false; 67 68 // telephony 69 boolean mHspaDataDistinguishable; 70 final TelephonyManager mPhone; 71 boolean mDataConnected; 72 IccCard.State mSimState = IccCard.State.READY; 73 int mPhoneState = TelephonyManager.CALL_STATE_IDLE; 74 int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN; 75 int mDataState = TelephonyManager.DATA_DISCONNECTED; 76 int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; 77 ServiceState mServiceState; 78 SignalStrength mSignalStrength; 79 int[] mDataIconList = TelephonyIcons.DATA_G[0]; 80 String mNetworkName; 81 String mNetworkNameDefault; 82 String mNetworkNameSeparator; 83 int mPhoneSignalIconId; 84 int mDataDirectionIconId; 85 int mDataDirectionOverlayIconId; 86 int mDataSignalIconId; 87 int mDataTypeIconId; 88 boolean mDataActive; 89 90 // wifi 91 final WifiManager mWifiManager; 92 AsyncChannel mWifiChannel; 93 boolean mWifiEnabled, mWifiConnected; 94 int mWifiLevel; 95 String mWifiSsid; 96 int mWifiIconId = 0; 97 int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE; 98 99 // bluetooth 100 private boolean mBluetoothTethered = false; 101 private int mBluetoothTetherIconId = 102 com.android.internal.R.drawable.stat_sys_tether_bluetooth; 103 104 // data connectivity (regardless of state, can we access the internet?) 105 // state of inet connection - 0 not connected, 100 connected 106 private int mInetCondition = 0; 107 private static final int INET_CONDITION_THRESHOLD = 50; 108 109 private boolean mAirplaneMode = false; 110 111 // our ui 112 Context mContext; 113 ArrayList<ImageView> mPhoneSignalIconViews = new ArrayList<ImageView>(); 114 ArrayList<ImageView> mDataDirectionIconViews = new ArrayList<ImageView>(); 115 ArrayList<ImageView> mDataDirectionOverlayIconViews = new ArrayList<ImageView>(); 116 ArrayList<ImageView> mWifiIconViews = new ArrayList<ImageView>(); 117 ArrayList<ImageView> mCombinedSignalIconViews = new ArrayList<ImageView>(); 118 ArrayList<ImageView> mDataTypeIconViews = new ArrayList<ImageView>(); 119 ArrayList<TextView> mLabelViews = new ArrayList<TextView>(); 120 int mLastPhoneSignalIconId = -1; 121 int mLastDataDirectionIconId = -1; 122 int mLastDataDirectionOverlayIconId = -1; 123 int mLastWifiIconId = -1; 124 int mLastCombinedSignalIconId = -1; 125 int mLastDataTypeIconId = -1; 126 String mLastLabel = ""; 127 128 // yuck -- stop doing this here and put it in the framework 129 IBatteryStats mBatteryStats; 130 131 /** 132 * Construct this controller object and register for updates. 133 */ 134 public NetworkController(Context context) { 135 mContext = context; 136 137 // set up the default wifi icon, used when no radios have ever appeared 138 updateWifiIcons(); 139 140 // telephony 141 mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 142 mPhone.listen(mPhoneStateListener, 143 PhoneStateListener.LISTEN_SERVICE_STATE 144 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS 145 | PhoneStateListener.LISTEN_CALL_STATE 146 | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE 147 | PhoneStateListener.LISTEN_DATA_ACTIVITY); 148 mHspaDataDistinguishable = mContext.getResources().getBoolean( 149 R.bool.config_hspa_data_distinguishable); 150 mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator); 151 mNetworkNameDefault = mContext.getString( 152 com.android.internal.R.string.lockscreen_carrier_default); 153 mNetworkName = mNetworkNameDefault; 154 155 // wifi 156 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 157 Handler handler = new WifiHandler(); 158 mWifiChannel = new AsyncChannel(); 159 Messenger wifiMessenger = mWifiManager.getMessenger(); 160 if (wifiMessenger != null) { 161 mWifiChannel.connect(mContext, handler, wifiMessenger); 162 } 163 164 // broadcasts 165 IntentFilter filter = new IntentFilter(); 166 filter.addAction(WifiManager.RSSI_CHANGED_ACTION); 167 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 168 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 169 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 170 filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION); 171 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 172 filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); 173 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 174 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 175 context.registerReceiver(this, filter); 176 177 // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it 178 updateAirplaneMode(); 179 180 // yuck 181 mBatteryStats = BatteryStatsService.getService(); 182 } 183 184 public void addPhoneSignalIconView(ImageView v) { 185 mPhoneSignalIconViews.add(v); 186 } 187 188 public void addDataDirectionIconView(ImageView v) { 189 mDataDirectionIconViews.add(v); 190 } 191 192 public void addDataDirectionOverlayIconView(ImageView v) { 193 mDataDirectionOverlayIconViews.add(v); 194 } 195 196 public void addWifiIconView(ImageView v) { 197 mWifiIconViews.add(v); 198 } 199 200 public void addCombinedSignalIconView(ImageView v) { 201 mCombinedSignalIconViews.add(v); 202 } 203 204 public void addDataTypeIconView(ImageView v) { 205 mDataTypeIconViews.add(v); 206 } 207 208 public void addLabelView(TextView v) { 209 mLabelViews.add(v); 210 } 211 212 @Override 213 public void onReceive(Context context, Intent intent) { 214 final String action = intent.getAction(); 215 if (action.equals(WifiManager.RSSI_CHANGED_ACTION) 216 || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) 217 || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 218 updateWifiState(intent); 219 refreshViews(); 220 } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { 221 updateSimState(intent); 222 updateDataIcon(); 223 refreshViews(); 224 } else if (action.equals(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION)) { 225 updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false), 226 intent.getStringExtra(Telephony.Intents.EXTRA_SPN), 227 intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false), 228 intent.getStringExtra(Telephony.Intents.EXTRA_PLMN)); 229 refreshViews(); 230 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) || 231 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) { 232 updateConnectivity(intent); 233 refreshViews(); 234 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { 235 refreshViews(); 236 } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 237 updateAirplaneMode(); 238 refreshViews(); 239 } 240 } 241 242 243 // ===== Telephony ============================================================== 244 245 PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 246 @Override 247 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 248 if (DEBUG) { 249 Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength); 250 } 251 mSignalStrength = signalStrength; 252 updateTelephonySignalStrength(); 253 refreshViews(); 254 } 255 256 @Override 257 public void onServiceStateChanged(ServiceState state) { 258 if (DEBUG) { 259 Slog.d(TAG, "onServiceStateChanged state=" + state.getState()); 260 } 261 mServiceState = state; 262 updateTelephonySignalStrength(); 263 updateDataIcon(); 264 refreshViews(); 265 } 266 267 @Override 268 public void onCallStateChanged(int state, String incomingNumber) { 269 if (DEBUG) { 270 Slog.d(TAG, "onCallStateChanged state=" + state); 271 } 272 // In cdma, if a voice call is made, RSSI should switch to 1x. 273 if (isCdma()) { 274 updateTelephonySignalStrength(); 275 refreshViews(); 276 } 277 } 278 279 @Override 280 public void onDataConnectionStateChanged(int state, int networkType) { 281 if (DEBUG) { 282 Slog.d(TAG, "onDataConnectionStateChanged: state=" + state 283 + " type=" + networkType); 284 } 285 mDataState = state; 286 mDataNetType = networkType; 287 if (state < 0) { 288 // device without a data connection 289 mSignalStrength = null; 290 } 291 updateDataNetType(); 292 updateDataIcon(); 293 refreshViews(); 294 } 295 296 @Override 297 public void onDataActivity(int direction) { 298 if (DEBUG) { 299 Slog.d(TAG, "onDataActivity: direction=" + direction); 300 } 301 mDataActivity = direction; 302 updateDataIcon(); 303 refreshViews(); 304 } 305 }; 306 307 private final void updateSimState(Intent intent) { 308 String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE); 309 if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { 310 mSimState = IccCard.State.ABSENT; 311 } 312 else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) { 313 mSimState = IccCard.State.READY; 314 } 315 else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { 316 final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON); 317 if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { 318 mSimState = IccCard.State.PIN_REQUIRED; 319 } 320 else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { 321 mSimState = IccCard.State.PUK_REQUIRED; 322 } 323 else { 324 mSimState = IccCard.State.NETWORK_LOCKED; 325 } 326 } else { 327 mSimState = IccCard.State.UNKNOWN; 328 } 329 } 330 331 private boolean isCdma() { 332 return (mSignalStrength != null) && !mSignalStrength.isGsm(); 333 } 334 335 private boolean hasService() { 336 if (mServiceState != null) { 337 switch (mServiceState.getState()) { 338 case ServiceState.STATE_OUT_OF_SERVICE: 339 case ServiceState.STATE_POWER_OFF: 340 return false; 341 default: 342 return true; 343 } 344 } else { 345 return false; 346 } 347 } 348 349 private boolean hasMobileDataFeature() { 350 // XXX: HAX: replace when a more reliable method is available 351 return (! "wifi-only".equals(SystemProperties.get("ro.carrier"))); 352 } 353 354 355 private void updateAirplaneMode() { 356 mAirplaneMode = (Settings.System.getInt(mContext.getContentResolver(), 357 Settings.System.AIRPLANE_MODE_ON, 0) == 1); 358 } 359 360 private final void updateTelephonySignalStrength() { 361 if (!hasService()) { 362 //Slog.d(TAG, "updateTelephonySignalStrength: no service"); 363 mPhoneSignalIconId = R.drawable.stat_sys_signal_null; 364 mDataSignalIconId = R.drawable.stat_sys_signal_0; // note we use 0 instead of null 365 } else { 366 if (mSignalStrength == null) { 367 mPhoneSignalIconId = R.drawable.stat_sys_signal_null; 368 mDataSignalIconId = R.drawable.stat_sys_signal_0; // note we use 0 instead of null 369 } else { 370 int iconLevel; 371 int[] iconList; 372 iconLevel = mSignalStrength.getLevel(); 373 if (isCdma()) { 374 if (isCdmaEri()) { 375 iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition]; 376 } else { 377 iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition]; 378 } 379 } else { 380 // Though mPhone is a Manager, this call is not an IPC 381 if (mPhone.isNetworkRoaming()) { 382 iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition]; 383 } else { 384 iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition]; 385 } 386 } 387 mPhoneSignalIconId = iconList[iconLevel]; 388 mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel]; 389 } 390 } 391 } 392 393 private final void updateDataNetType() { 394 switch (mDataNetType) { 395 case TelephonyManager.NETWORK_TYPE_UNKNOWN: 396 mDataIconList = TelephonyIcons.DATA_G[mInetCondition]; 397 mDataTypeIconId = 0; 398 break; 399 case TelephonyManager.NETWORK_TYPE_EDGE: 400 mDataIconList = TelephonyIcons.DATA_E[mInetCondition]; 401 mDataTypeIconId = R.drawable.stat_sys_signal_edge; 402 break; 403 case TelephonyManager.NETWORK_TYPE_UMTS: 404 mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; 405 mDataTypeIconId = R.drawable.stat_sys_signal_3g; 406 break; 407 case TelephonyManager.NETWORK_TYPE_HSDPA: 408 case TelephonyManager.NETWORK_TYPE_HSUPA: 409 case TelephonyManager.NETWORK_TYPE_HSPA: 410 if (mHspaDataDistinguishable) { 411 mDataIconList = TelephonyIcons.DATA_H[mInetCondition]; 412 mDataTypeIconId = R.drawable.stat_sys_signal_hsdpa; 413 } else { 414 mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; 415 mDataTypeIconId = R.drawable.stat_sys_signal_3g; 416 } 417 break; 418 case TelephonyManager.NETWORK_TYPE_CDMA: 419 // display 1xRTT for IS95A/B 420 mDataIconList = TelephonyIcons.DATA_1X[mInetCondition]; 421 mDataTypeIconId = R.drawable.stat_sys_signal_1x; 422 break; 423 case TelephonyManager.NETWORK_TYPE_1xRTT: 424 mDataIconList = TelephonyIcons.DATA_1X[mInetCondition]; 425 mDataTypeIconId = R.drawable.stat_sys_signal_1x; 426 break; 427 case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through 428 case TelephonyManager.NETWORK_TYPE_EVDO_A: 429 case TelephonyManager.NETWORK_TYPE_EVDO_B: 430 case TelephonyManager.NETWORK_TYPE_EHRPD: 431 mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; 432 mDataTypeIconId = R.drawable.stat_sys_signal_3g; 433 break; 434 case TelephonyManager.NETWORK_TYPE_LTE: 435 mDataIconList = TelephonyIcons.DATA_4G[mInetCondition]; 436 mDataTypeIconId = R.drawable.stat_sys_signal_4g; 437 break; 438 default: 439 mDataIconList = TelephonyIcons.DATA_G[mInetCondition]; 440 mDataTypeIconId = R.drawable.stat_sys_signal_gprs; 441 break; 442 } 443 if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) { 444 mDataTypeIconId = R.drawable.stat_sys_signal_roam; 445 } 446 } 447 448 boolean isCdmaEri() { 449 if (mServiceState != null) { 450 final int iconIndex = mServiceState.getCdmaEriIconIndex(); 451 if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) { 452 final int iconMode = mServiceState.getCdmaEriIconMode(); 453 if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL 454 || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) { 455 return true; 456 } 457 } 458 } 459 return false; 460 } 461 462 private final void updateDataIcon() { 463 int iconId; 464 boolean visible = true; 465 466 if (!isCdma()) { 467 // GSM case, we have to check also the sim state 468 if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) { 469 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { 470 switch (mDataActivity) { 471 case TelephonyManager.DATA_ACTIVITY_IN: 472 iconId = mDataIconList[1]; 473 break; 474 case TelephonyManager.DATA_ACTIVITY_OUT: 475 iconId = mDataIconList[2]; 476 break; 477 case TelephonyManager.DATA_ACTIVITY_INOUT: 478 iconId = mDataIconList[3]; 479 break; 480 default: 481 iconId = mDataIconList[0]; 482 break; 483 } 484 mDataDirectionIconId = iconId; 485 } else { 486 iconId = 0; 487 visible = false; 488 } 489 } else { 490 iconId = R.drawable.stat_sys_no_sim; 491 } 492 } else { 493 // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT 494 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { 495 switch (mDataActivity) { 496 case TelephonyManager.DATA_ACTIVITY_IN: 497 iconId = mDataIconList[1]; 498 break; 499 case TelephonyManager.DATA_ACTIVITY_OUT: 500 iconId = mDataIconList[2]; 501 break; 502 case TelephonyManager.DATA_ACTIVITY_INOUT: 503 iconId = mDataIconList[3]; 504 break; 505 case TelephonyManager.DATA_ACTIVITY_DORMANT: 506 default: 507 iconId = mDataIconList[0]; 508 break; 509 } 510 } else { 511 iconId = 0; 512 visible = false; 513 } 514 } 515 516 // yuck - this should NOT be done by the status bar 517 long ident = Binder.clearCallingIdentity(); 518 try { 519 mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible); 520 } catch (RemoteException e) { 521 } finally { 522 Binder.restoreCallingIdentity(ident); 523 } 524 525 mDataDirectionIconId = iconId; 526 mDataConnected = visible; 527 } 528 529 void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) { 530 if (false) { 531 Slog.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn 532 + " showPlmn=" + showPlmn + " plmn=" + plmn); 533 } 534 StringBuilder str = new StringBuilder(); 535 boolean something = false; 536 if (showPlmn && plmn != null) { 537 str.append(plmn); 538 something = true; 539 } 540 if (showSpn && spn != null) { 541 if (something) { 542 str.append(mNetworkNameSeparator); 543 } 544 str.append(spn); 545 something = true; 546 } 547 if (something) { 548 mNetworkName = str.toString(); 549 } else { 550 mNetworkName = mNetworkNameDefault; 551 } 552 } 553 554 // ===== Wifi =================================================================== 555 556 class WifiHandler extends Handler { 557 @Override 558 public void handleMessage(Message msg) { 559 switch (msg.what) { 560 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 561 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 562 mWifiChannel.sendMessage(Message.obtain(this, 563 AsyncChannel.CMD_CHANNEL_FULL_CONNECTION)); 564 } else { 565 Slog.e(TAG, "Failed to connect to wifi"); 566 } 567 break; 568 case WifiManager.DATA_ACTIVITY_NOTIFICATION: 569 if (msg.arg1 != mWifiActivity) { 570 mWifiActivity = msg.arg1; 571 refreshViews(); 572 } 573 break; 574 default: 575 //Ignore 576 break; 577 } 578 } 579 } 580 581 private void updateWifiState(Intent intent) { 582 final String action = intent.getAction(); 583 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 584 mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 585 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; 586 587 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 588 final NetworkInfo networkInfo = (NetworkInfo) 589 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 590 boolean wasConnected = mWifiConnected; 591 mWifiConnected = networkInfo != null && networkInfo.isConnected(); 592 // If we just connected, grab the inintial signal strength and ssid 593 if (mWifiConnected && !wasConnected) { 594 WifiInfo info = mWifiManager.getConnectionInfo(); 595 if (info != null) { 596 mWifiLevel = WifiManager.calculateSignalLevel(info.getRssi(), 597 WifiIcons.WIFI_LEVEL_COUNT); 598 mWifiSsid = huntForSsid(info); 599 } else { 600 mWifiLevel = 0; 601 mWifiSsid = null; 602 } 603 } else if (!mWifiConnected) { 604 mWifiLevel = 0; 605 mWifiSsid = null; 606 } 607 608 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { 609 if (mWifiConnected) { 610 final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); 611 mWifiLevel = WifiManager.calculateSignalLevel(newRssi, WifiIcons.WIFI_LEVEL_COUNT); 612 } 613 } 614 615 updateWifiIcons(); 616 } 617 618 private void updateWifiIcons() { 619 if (mWifiConnected) { 620 mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel]; 621 } else { 622 mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]; 623 } 624 } 625 626 private String huntForSsid(WifiInfo info) { 627 String ssid = info.getSSID(); 628 if (ssid != null) { 629 return ssid; 630 } 631 // OK, it's not in the connectionInfo; we have to go hunting for it 632 List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks(); 633 for (WifiConfiguration net : networks) { 634 if (net.networkId == info.getNetworkId()) { 635 return net.SSID; 636 } 637 } 638 return null; 639 } 640 641 642 // ===== Full or limited Internet connectivity ================================== 643 644 private void updateConnectivity(Intent intent) { 645 NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra( 646 ConnectivityManager.EXTRA_NETWORK_INFO)); 647 int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0); 648 649 int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0); 650 651 switch (info.getType()) { 652 case ConnectivityManager.TYPE_MOBILE: 653 mInetCondition = inetCondition; 654 updateDataNetType(); 655 updateDataIcon(); 656 updateTelephonySignalStrength(); // apply any change in connectionStatus 657 break; 658 case ConnectivityManager.TYPE_WIFI: 659 mInetCondition = inetCondition; 660 updateWifiIcons(); 661 break; 662 case ConnectivityManager.TYPE_BLUETOOTH: 663 mInetCondition = inetCondition; 664 if (info != null) { 665 mBluetoothTethered = info.isConnected() ? true: false; 666 } else { 667 mBluetoothTethered = false; 668 } 669 break; 670 } 671 } 672 673 674 // ===== Update the views ======================================================= 675 676 // figure out what to show- there should be one connected network or nothing 677 // General order of preference is: wifi, 3G than bluetooth. This might vary by product. 678 void refreshViews() { 679 Context context = mContext; 680 681 int combinedSignalIconId; 682 int dataDirectionOverlayIconId = 0; 683 int dataTypeIconId; 684 String label; 685 int N; 686 687 if (mWifiConnected) { 688 if (mWifiSsid == null) { 689 label = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid); 690 } else { 691 label = mWifiSsid; 692 switch (mWifiActivity) { 693 case WifiManager.DATA_ACTIVITY_IN: 694 dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_in; 695 break; 696 case WifiManager.DATA_ACTIVITY_OUT: 697 dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_out; 698 break; 699 case WifiManager.DATA_ACTIVITY_INOUT: 700 dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_inout; 701 break; 702 case WifiManager.DATA_ACTIVITY_NONE: 703 break; 704 } 705 } 706 combinedSignalIconId = mWifiIconId; 707 dataTypeIconId = 0; 708 } else if (mDataConnected) { 709 label = mNetworkName; 710 combinedSignalIconId = mDataSignalIconId; 711 switch (mDataActivity) { 712 case TelephonyManager.DATA_ACTIVITY_IN: 713 dataDirectionOverlayIconId = R.drawable.stat_sys_signal_in; 714 break; 715 case TelephonyManager.DATA_ACTIVITY_OUT: 716 dataDirectionOverlayIconId = R.drawable.stat_sys_signal_out; 717 break; 718 case TelephonyManager.DATA_ACTIVITY_INOUT: 719 dataDirectionOverlayIconId = R.drawable.stat_sys_signal_inout; 720 break; 721 default: 722 dataDirectionOverlayIconId = 0; 723 break; 724 } 725 combinedSignalIconId = mDataSignalIconId; 726 dataTypeIconId = mDataTypeIconId; 727 } else if (mBluetoothTethered) { 728 label = mContext.getString(R.string.bluetooth_tethered); 729 combinedSignalIconId = mBluetoothTetherIconId; 730 dataTypeIconId = 0; 731 } else if (mAirplaneMode && 732 (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) { 733 // Only display the flight-mode icon if not in "emergency calls only" mode. 734 label = context.getString(R.string.status_bar_settings_signal_meter_disconnected); 735 combinedSignalIconId = R.drawable.stat_sys_signal_flightmode; 736 dataTypeIconId = 0; 737 } else { 738 label = context.getString(R.string.status_bar_settings_signal_meter_disconnected); 739 // On devices without mobile radios, we want to show the wifi icon 740 combinedSignalIconId = 741 hasMobileDataFeature() ? mDataSignalIconId : mWifiIconId; 742 dataTypeIconId = 0; 743 } 744 745 if (DEBUG) { 746 Slog.d(TAG, "refreshViews combinedSignalIconId=0x" 747 + Integer.toHexString(combinedSignalIconId) 748 + "/" + getResourceName(combinedSignalIconId) 749 + " dataDirectionOverlayIconId=0x" + Integer.toHexString(dataDirectionOverlayIconId) 750 + " mAirplaneMode=" + mAirplaneMode 751 + " mDataActivity=" + mDataActivity 752 + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId) 753 + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId) 754 + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId) 755 + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId) 756 + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId) 757 + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId)); 758 } 759 760 // the phone icon on phones 761 if (mLastPhoneSignalIconId != mPhoneSignalIconId) { 762 mLastPhoneSignalIconId = mPhoneSignalIconId; 763 N = mPhoneSignalIconViews.size(); 764 for (int i=0; i<N; i++) { 765 final ImageView v = mPhoneSignalIconViews.get(i); 766 v.setImageResource(mPhoneSignalIconId); 767 } 768 } 769 770 // the data icon on phones 771 if (mLastDataDirectionIconId != mDataDirectionIconId) { 772 mLastDataDirectionIconId = mDataDirectionIconId; 773 N = mDataDirectionIconViews.size(); 774 for (int i=0; i<N; i++) { 775 final ImageView v = mDataDirectionIconViews.get(i); 776 v.setImageResource(mDataDirectionIconId); 777 } 778 } 779 780 // the wifi icon on phones 781 if (mLastWifiIconId != mWifiIconId) { 782 mLastWifiIconId = mWifiIconId; 783 N = mWifiIconViews.size(); 784 for (int i=0; i<N; i++) { 785 final ImageView v = mWifiIconViews.get(i); 786 v.setImageResource(mWifiIconId); 787 } 788 } 789 790 // the combined data signal icon 791 if (mLastCombinedSignalIconId != combinedSignalIconId) { 792 mLastCombinedSignalIconId = combinedSignalIconId; 793 N = mCombinedSignalIconViews.size(); 794 for (int i=0; i<N; i++) { 795 final ImageView v = mCombinedSignalIconViews.get(i); 796 v.setImageResource(combinedSignalIconId); 797 } 798 } 799 800 // the data network type overlay 801 if (mLastDataTypeIconId != dataTypeIconId) { 802 mLastDataTypeIconId = dataTypeIconId; 803 N = mDataTypeIconViews.size(); 804 for (int i=0; i<N; i++) { 805 final ImageView v = mDataTypeIconViews.get(i); 806 if (dataTypeIconId == 0) { 807 v.setVisibility(View.INVISIBLE); 808 } else { 809 v.setVisibility(View.VISIBLE); 810 v.setImageResource(dataTypeIconId); 811 } 812 } 813 } 814 815 // the data direction overlay 816 if (mLastDataDirectionOverlayIconId != dataDirectionOverlayIconId) { 817 if (DEBUG) { 818 Slog.d(TAG, "changing data overlay icon id to " + dataDirectionOverlayIconId); 819 } 820 mLastDataDirectionOverlayIconId = dataDirectionOverlayIconId; 821 N = mDataDirectionOverlayIconViews.size(); 822 for (int i=0; i<N; i++) { 823 final ImageView v = mDataDirectionOverlayIconViews.get(i); 824 if (dataDirectionOverlayIconId == 0) { 825 v.setVisibility(View.INVISIBLE); 826 } else { 827 v.setVisibility(View.VISIBLE); 828 v.setImageResource(dataDirectionOverlayIconId); 829 } 830 } 831 } 832 833 // the label in the notification panel 834 if (!mLastLabel.equals(label)) { 835 mLastLabel = label; 836 N = mLabelViews.size(); 837 for (int i=0; i<N; i++) { 838 TextView v = mLabelViews.get(i); 839 v.setText(label); 840 } 841 } 842 } 843 844 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 845 pw.println(" - telephony ------"); 846 pw.print(" mHspaDataDistinguishable="); 847 pw.println(mHspaDataDistinguishable); 848 pw.print(" mDataConnected="); 849 pw.println(mDataConnected); 850 pw.print(" mSimState="); 851 pw.println(mSimState); 852 pw.print(" mPhoneState="); 853 pw.println(mPhoneState); 854 pw.print(" mDataState="); 855 pw.println(mDataState); 856 pw.print(" mDataActivity="); 857 pw.println(mDataActivity); 858 pw.print(" mServiceState="); 859 pw.println(mServiceState); 860 pw.print(" mNetworkName="); 861 pw.println(mNetworkName); 862 pw.print(" mNetworkNameDefault="); 863 pw.println(mNetworkNameDefault); 864 pw.print(" mNetworkNameSeparator="); 865 pw.println(mNetworkNameSeparator); 866 pw.print(" mPhoneSignalIconId=0x"); 867 pw.print(Integer.toHexString(mPhoneSignalIconId)); 868 pw.print("/"); 869 pw.println(getResourceName(mPhoneSignalIconId)); 870 pw.print(" mDataDirectionIconId="); 871 pw.print(Integer.toHexString(mDataDirectionIconId)); 872 pw.print("/"); 873 pw.println(getResourceName(mDataDirectionIconId)); 874 pw.print(" mDataSignalIconId="); 875 pw.print(Integer.toHexString(mDataSignalIconId)); 876 pw.print("/"); 877 pw.println(getResourceName(mDataSignalIconId)); 878 pw.print(" mDataTypeIconId="); 879 pw.print(Integer.toHexString(mDataTypeIconId)); 880 pw.print("/"); 881 pw.println(getResourceName(mDataTypeIconId)); 882 883 pw.println(" - wifi ------"); 884 pw.print(" mWifiEnabled="); 885 pw.println(mWifiEnabled); 886 pw.print(" mWifiConnected="); 887 pw.println(mWifiConnected); 888 pw.print(" mWifiLevel="); 889 pw.println(mWifiLevel); 890 pw.print(" mWifiSsid="); 891 pw.println(mWifiSsid); 892 pw.print(" mWifiIconId="); 893 pw.println(mWifiIconId); 894 pw.print(" mWifiActivity="); 895 pw.println(mWifiActivity); 896 897 898 pw.println(" - Bluetooth ----"); 899 pw.print(" mBtReverseTethered="); 900 pw.println(mBluetoothTethered); 901 902 pw.println(" - connectivity ------"); 903 pw.print(" mInetCondition="); 904 pw.println(mInetCondition); 905 906 pw.println(" - icons ------"); 907 pw.print(" mLastPhoneSignalIconId=0x"); 908 pw.print(Integer.toHexString(mLastPhoneSignalIconId)); 909 pw.print("/"); 910 pw.println(getResourceName(mLastPhoneSignalIconId)); 911 pw.print(" mLastDataDirectionIconId=0x"); 912 pw.print(Integer.toHexString(mLastDataDirectionIconId)); 913 pw.print("/"); 914 pw.println(getResourceName(mLastDataDirectionIconId)); 915 pw.print(" mLastDataDirectionOverlayIconId=0x"); 916 pw.print(Integer.toHexString(mLastDataDirectionOverlayIconId)); 917 pw.print("/"); 918 pw.println(getResourceName(mLastDataDirectionOverlayIconId)); 919 pw.print(" mLastWifiIconId=0x"); 920 pw.print(Integer.toHexString(mLastWifiIconId)); 921 pw.print("/"); 922 pw.println(getResourceName(mLastWifiIconId)); 923 pw.print(" mLastCombinedSignalIconId=0x"); 924 pw.print(Integer.toHexString(mLastCombinedSignalIconId)); 925 pw.print("/"); 926 pw.println(getResourceName(mLastCombinedSignalIconId)); 927 pw.print(" mLastDataTypeIconId=0x"); 928 pw.print(Integer.toHexString(mLastDataTypeIconId)); 929 pw.print("/"); 930 pw.println(getResourceName(mLastCombinedSignalIconId)); 931 pw.print(" mLastLabel="); 932 pw.print(mLastLabel); 933 } 934 935 private String getResourceName(int resId) { 936 if (resId == 0) { 937 final Resources res = mContext.getResources(); 938 try { 939 return res.getResourceName(resId); 940 } catch (android.content.res.Resources.NotFoundException ex) { 941 return "(unknown)"; 942 } 943 } else { 944 return "(null)"; 945 } 946 } 947 948} 949