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