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