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