NetworkController.java revision 9d7d62801ddb206d2ea96d74864a9edfe54d2eee
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 final int iconIndex = mServiceState.getCdmaEriIconIndex(); 450 if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) { 451 final int iconMode = mServiceState.getCdmaEriIconMode(); 452 if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL 453 || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) { 454 return true; 455 } 456 } 457 return false; 458 } 459 460 private final void updateDataIcon() { 461 int iconId; 462 boolean visible = true; 463 464 if (!isCdma()) { 465 // GSM case, we have to check also the sim state 466 if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) { 467 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { 468 switch (mDataActivity) { 469 case TelephonyManager.DATA_ACTIVITY_IN: 470 iconId = mDataIconList[1]; 471 break; 472 case TelephonyManager.DATA_ACTIVITY_OUT: 473 iconId = mDataIconList[2]; 474 break; 475 case TelephonyManager.DATA_ACTIVITY_INOUT: 476 iconId = mDataIconList[3]; 477 break; 478 default: 479 iconId = mDataIconList[0]; 480 break; 481 } 482 mDataDirectionIconId = iconId; 483 } else { 484 iconId = 0; 485 visible = false; 486 } 487 } else { 488 iconId = R.drawable.stat_sys_no_sim; 489 } 490 } else { 491 // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT 492 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { 493 switch (mDataActivity) { 494 case TelephonyManager.DATA_ACTIVITY_IN: 495 iconId = mDataIconList[1]; 496 break; 497 case TelephonyManager.DATA_ACTIVITY_OUT: 498 iconId = mDataIconList[2]; 499 break; 500 case TelephonyManager.DATA_ACTIVITY_INOUT: 501 iconId = mDataIconList[3]; 502 break; 503 case TelephonyManager.DATA_ACTIVITY_DORMANT: 504 default: 505 iconId = mDataIconList[0]; 506 break; 507 } 508 } else { 509 iconId = 0; 510 visible = false; 511 } 512 } 513 514 // yuck - this should NOT be done by the status bar 515 long ident = Binder.clearCallingIdentity(); 516 try { 517 mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible); 518 } catch (RemoteException e) { 519 } finally { 520 Binder.restoreCallingIdentity(ident); 521 } 522 523 mDataDirectionIconId = iconId; 524 mDataConnected = visible; 525 } 526 527 void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) { 528 if (false) { 529 Slog.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn 530 + " showPlmn=" + showPlmn + " plmn=" + plmn); 531 } 532 StringBuilder str = new StringBuilder(); 533 boolean something = false; 534 if (showPlmn && plmn != null) { 535 str.append(plmn); 536 something = true; 537 } 538 if (showSpn && spn != null) { 539 if (something) { 540 str.append(mNetworkNameSeparator); 541 } 542 str.append(spn); 543 something = true; 544 } 545 if (something) { 546 mNetworkName = str.toString(); 547 } else { 548 mNetworkName = mNetworkNameDefault; 549 } 550 } 551 552 // ===== Wifi =================================================================== 553 554 class WifiHandler extends Handler { 555 @Override 556 public void handleMessage(Message msg) { 557 switch (msg.what) { 558 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 559 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 560 mWifiChannel.sendMessage(Message.obtain(this, 561 AsyncChannel.CMD_CHANNEL_FULL_CONNECTION)); 562 } else { 563 Slog.e(TAG, "Failed to connect to wifi"); 564 } 565 break; 566 case WifiManager.DATA_ACTIVITY_NOTIFICATION: 567 if (msg.arg1 != mWifiActivity) { 568 mWifiActivity = msg.arg1; 569 refreshViews(); 570 } 571 break; 572 default: 573 //Ignore 574 break; 575 } 576 } 577 } 578 579 private void updateWifiState(Intent intent) { 580 final String action = intent.getAction(); 581 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 582 mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 583 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; 584 585 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 586 final NetworkInfo networkInfo = (NetworkInfo) 587 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 588 boolean wasConnected = mWifiConnected; 589 mWifiConnected = networkInfo != null && networkInfo.isConnected(); 590 // If we just connected, grab the inintial signal strength and ssid 591 if (mWifiConnected && !wasConnected) { 592 WifiInfo info = mWifiManager.getConnectionInfo(); 593 if (info != null) { 594 mWifiLevel = WifiManager.calculateSignalLevel(info.getRssi(), 595 WifiIcons.WIFI_LEVEL_COUNT); 596 mWifiSsid = huntForSsid(info); 597 } else { 598 mWifiLevel = 0; 599 mWifiSsid = null; 600 } 601 } else if (!mWifiConnected) { 602 mWifiLevel = 0; 603 mWifiSsid = null; 604 } 605 606 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { 607 if (mWifiConnected) { 608 final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); 609 mWifiLevel = WifiManager.calculateSignalLevel(newRssi, WifiIcons.WIFI_LEVEL_COUNT); 610 } 611 } 612 613 updateWifiIcons(); 614 } 615 616 private void updateWifiIcons() { 617 if (mWifiConnected) { 618 mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel]; 619 } else { 620 mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]; 621 } 622 } 623 624 private String huntForSsid(WifiInfo info) { 625 String ssid = info.getSSID(); 626 if (ssid != null) { 627 return ssid; 628 } 629 // OK, it's not in the connectionInfo; we have to go hunting for it 630 List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks(); 631 for (WifiConfiguration net : networks) { 632 if (net.networkId == info.getNetworkId()) { 633 return net.SSID; 634 } 635 } 636 return null; 637 } 638 639 640 // ===== Full or limited Internet connectivity ================================== 641 642 private void updateConnectivity(Intent intent) { 643 NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra( 644 ConnectivityManager.EXTRA_NETWORK_INFO)); 645 int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0); 646 647 int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0); 648 649 switch (info.getType()) { 650 case ConnectivityManager.TYPE_MOBILE: 651 mInetCondition = inetCondition; 652 updateDataNetType(); 653 updateDataIcon(); 654 updateTelephonySignalStrength(); // apply any change in connectionStatus 655 break; 656 case ConnectivityManager.TYPE_WIFI: 657 mInetCondition = inetCondition; 658 updateWifiIcons(); 659 break; 660 case ConnectivityManager.TYPE_BLUETOOTH: 661 mInetCondition = inetCondition; 662 if (info != null) { 663 mBluetoothTethered = info.isConnected() ? true: false; 664 } else { 665 mBluetoothTethered = false; 666 } 667 break; 668 } 669 } 670 671 672 // ===== Update the views ======================================================= 673 674 // figure out what to show- there should be one connected network or nothing 675 // General order of preference is: wifi, 3G than bluetooth. This might vary by product. 676 void refreshViews() { 677 Context context = mContext; 678 679 int combinedSignalIconId; 680 int dataDirectionOverlayIconId = 0; 681 int dataTypeIconId; 682 String label; 683 int N; 684 685 if (mWifiConnected) { 686 if (mWifiSsid == null) { 687 label = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid); 688 } else { 689 label = mWifiSsid; 690 switch (mWifiActivity) { 691 case WifiManager.DATA_ACTIVITY_IN: 692 dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_in; 693 break; 694 case WifiManager.DATA_ACTIVITY_OUT: 695 dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_out; 696 break; 697 case WifiManager.DATA_ACTIVITY_INOUT: 698 dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_inout; 699 break; 700 case WifiManager.DATA_ACTIVITY_NONE: 701 break; 702 } 703 } 704 combinedSignalIconId = mWifiIconId; 705 dataTypeIconId = 0; 706 } else if (mDataConnected) { 707 label = mNetworkName; 708 combinedSignalIconId = mDataSignalIconId; 709 switch (mDataActivity) { 710 case TelephonyManager.DATA_ACTIVITY_IN: 711 dataDirectionOverlayIconId = R.drawable.stat_sys_signal_in; 712 break; 713 case TelephonyManager.DATA_ACTIVITY_OUT: 714 dataDirectionOverlayIconId = R.drawable.stat_sys_signal_out; 715 break; 716 case TelephonyManager.DATA_ACTIVITY_INOUT: 717 dataDirectionOverlayIconId = R.drawable.stat_sys_signal_inout; 718 break; 719 default: 720 dataDirectionOverlayIconId = 0; 721 break; 722 } 723 combinedSignalIconId = mDataSignalIconId; 724 dataTypeIconId = mDataTypeIconId; 725 } else if (mBluetoothTethered) { 726 label = mContext.getString(R.string.bluetooth_tethered); 727 combinedSignalIconId = mBluetoothTetherIconId; 728 dataTypeIconId = 0; 729 } else if (mAirplaneMode && 730 (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) { 731 // Only display the flight-mode icon if not in "emergency calls only" mode. 732 label = context.getString(R.string.status_bar_settings_signal_meter_disconnected); 733 combinedSignalIconId = R.drawable.stat_sys_signal_flightmode; 734 dataTypeIconId = 0; 735 } else { 736 label = context.getString(R.string.status_bar_settings_signal_meter_disconnected); 737 // On devices without mobile radios, we want to show the wifi icon 738 combinedSignalIconId = 739 hasMobileDataFeature() ? mDataSignalIconId : mWifiIconId; 740 dataTypeIconId = 0; 741 } 742 743 if (DEBUG) { 744 Slog.d(TAG, "refreshViews combinedSignalIconId=0x" 745 + Integer.toHexString(combinedSignalIconId) 746 + "/" + getResourceName(combinedSignalIconId) 747 + " dataDirectionOverlayIconId=0x" + Integer.toHexString(dataDirectionOverlayIconId) 748 + " mAirplaneMode=" + mAirplaneMode 749 + " mDataActivity=" + mDataActivity 750 + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId) 751 + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId) 752 + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId) 753 + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId) 754 + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId) 755 + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId)); 756 } 757 758 // the phone icon on phones 759 if (mLastPhoneSignalIconId != mPhoneSignalIconId) { 760 mLastPhoneSignalIconId = mPhoneSignalIconId; 761 N = mPhoneSignalIconViews.size(); 762 for (int i=0; i<N; i++) { 763 final ImageView v = mPhoneSignalIconViews.get(i); 764 v.setImageResource(mPhoneSignalIconId); 765 } 766 } 767 768 // the data icon on phones 769 if (mLastDataDirectionIconId != mDataDirectionIconId) { 770 mLastDataDirectionIconId = mDataDirectionIconId; 771 N = mDataDirectionIconViews.size(); 772 for (int i=0; i<N; i++) { 773 final ImageView v = mDataDirectionIconViews.get(i); 774 v.setImageResource(mDataDirectionIconId); 775 } 776 } 777 778 // the wifi icon on phones 779 if (mLastWifiIconId != mWifiIconId) { 780 mLastWifiIconId = mWifiIconId; 781 N = mWifiIconViews.size(); 782 for (int i=0; i<N; i++) { 783 final ImageView v = mWifiIconViews.get(i); 784 v.setImageResource(mWifiIconId); 785 } 786 } 787 788 // the combined data signal icon 789 if (mLastCombinedSignalIconId != combinedSignalIconId) { 790 mLastCombinedSignalIconId = combinedSignalIconId; 791 N = mCombinedSignalIconViews.size(); 792 for (int i=0; i<N; i++) { 793 final ImageView v = mCombinedSignalIconViews.get(i); 794 v.setImageResource(combinedSignalIconId); 795 } 796 } 797 798 // the data network type overlay 799 if (mLastDataTypeIconId != dataTypeIconId) { 800 mLastDataTypeIconId = dataTypeIconId; 801 N = mDataTypeIconViews.size(); 802 for (int i=0; i<N; i++) { 803 final ImageView v = mDataTypeIconViews.get(i); 804 if (dataTypeIconId == 0) { 805 v.setVisibility(View.INVISIBLE); 806 } else { 807 v.setVisibility(View.VISIBLE); 808 v.setImageResource(dataTypeIconId); 809 } 810 } 811 } 812 813 // the data direction overlay 814 if (mLastDataDirectionOverlayIconId != dataDirectionOverlayIconId) { 815 Slog.d(TAG, "changing data overlay icon id to " + dataDirectionOverlayIconId); 816 mLastDataDirectionOverlayIconId = dataDirectionOverlayIconId; 817 N = mDataDirectionOverlayIconViews.size(); 818 for (int i=0; i<N; i++) { 819 final ImageView v = mDataDirectionOverlayIconViews.get(i); 820 if (dataDirectionOverlayIconId == 0) { 821 v.setVisibility(View.INVISIBLE); 822 } else { 823 v.setVisibility(View.VISIBLE); 824 v.setImageResource(dataDirectionOverlayIconId); 825 } 826 } 827 } 828 829 // the label in the notification panel 830 if (!mLastLabel.equals(label)) { 831 mLastLabel = label; 832 N = mLabelViews.size(); 833 for (int i=0; i<N; i++) { 834 TextView v = mLabelViews.get(i); 835 v.setText(label); 836 } 837 } 838 } 839 840 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 841 pw.println(" - telephony ------"); 842 pw.print(" mHspaDataDistinguishable="); 843 pw.println(mHspaDataDistinguishable); 844 pw.print(" mDataConnected="); 845 pw.println(mDataConnected); 846 pw.print(" mSimState="); 847 pw.println(mSimState); 848 pw.print(" mPhoneState="); 849 pw.println(mPhoneState); 850 pw.print(" mDataState="); 851 pw.println(mDataState); 852 pw.print(" mDataActivity="); 853 pw.println(mDataActivity); 854 pw.print(" mServiceState="); 855 pw.println(mServiceState.toString()); 856 pw.print(" mNetworkName="); 857 pw.println(mNetworkName); 858 pw.print(" mNetworkNameDefault="); 859 pw.println(mNetworkNameDefault); 860 pw.print(" mNetworkNameSeparator="); 861 pw.println(mNetworkNameSeparator); 862 pw.print(" mPhoneSignalIconId=0x"); 863 pw.print(Integer.toHexString(mPhoneSignalIconId)); 864 pw.print("/"); 865 pw.println(getResourceName(mPhoneSignalIconId)); 866 pw.print(" mDataDirectionIconId="); 867 pw.print(Integer.toHexString(mDataDirectionIconId)); 868 pw.print("/"); 869 pw.println(getResourceName(mDataDirectionIconId)); 870 pw.print(" mDataSignalIconId="); 871 pw.print(Integer.toHexString(mDataSignalIconId)); 872 pw.print("/"); 873 pw.println(getResourceName(mDataSignalIconId)); 874 pw.print(" mDataTypeIconId="); 875 pw.print(Integer.toHexString(mDataTypeIconId)); 876 pw.print("/"); 877 pw.println(getResourceName(mDataTypeIconId)); 878 879 pw.println(" - wifi ------"); 880 pw.print(" mWifiEnabled="); 881 pw.println(mWifiEnabled); 882 pw.print(" mWifiConnected="); 883 pw.println(mWifiConnected); 884 pw.print(" mWifiLevel="); 885 pw.println(mWifiLevel); 886 pw.print(" mWifiSsid="); 887 pw.println(mWifiSsid); 888 pw.print(" mWifiIconId="); 889 pw.println(mWifiIconId); 890 pw.print(" mWifiActivity="); 891 pw.println(mWifiActivity); 892 893 894 pw.println(" - Bluetooth ----"); 895 pw.print(" mBtReverseTethered="); 896 pw.println(mBluetoothTethered); 897 898 pw.println(" - connectivity ------"); 899 pw.print(" mInetCondition="); 900 pw.println(mInetCondition); 901 902 pw.println(" - icons ------"); 903 pw.print(" mLastPhoneSignalIconId=0x"); 904 pw.print(Integer.toHexString(mLastPhoneSignalIconId)); 905 pw.print("/"); 906 pw.println(getResourceName(mLastPhoneSignalIconId)); 907 pw.print(" mLastDataDirectionIconId=0x"); 908 pw.print(Integer.toHexString(mLastDataDirectionIconId)); 909 pw.print("/"); 910 pw.println(getResourceName(mLastDataDirectionIconId)); 911 pw.print(" mLastDataDirectionOverlayIconId=0x"); 912 pw.print(Integer.toHexString(mLastDataDirectionOverlayIconId)); 913 pw.print("/"); 914 pw.println(getResourceName(mLastDataDirectionOverlayIconId)); 915 pw.print(" mLastWifiIconId=0x"); 916 pw.print(Integer.toHexString(mLastWifiIconId)); 917 pw.print("/"); 918 pw.println(getResourceName(mLastWifiIconId)); 919 pw.print(" mLastCombinedSignalIconId=0x"); 920 pw.print(Integer.toHexString(mLastCombinedSignalIconId)); 921 pw.print("/"); 922 pw.println(getResourceName(mLastCombinedSignalIconId)); 923 pw.print(" mLastDataTypeIconId=0x"); 924 pw.print(Integer.toHexString(mLastDataTypeIconId)); 925 pw.print("/"); 926 pw.println(getResourceName(mLastCombinedSignalIconId)); 927 pw.print(" mLastLabel="); 928 pw.print(mLastLabel); 929 } 930 931 private String getResourceName(int resId) { 932 if (resId == 0) { 933 final Resources res = mContext.getResources(); 934 try { 935 return res.getResourceName(resId); 936 } catch (android.content.res.Resources.NotFoundException ex) { 937 return "(unknown)"; 938 } 939 } else { 940 return "(null)"; 941 } 942 } 943 944} 945