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 17 package com.android.systemui.statusbar.policy; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.content.res.Resources; 24 import android.net.ConnectivityManager; 25 import android.net.NetworkCapabilities; 26 import android.net.wifi.WifiManager; 27 import android.os.AsyncTask; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.Looper; 31 import android.provider.Settings; 32 import android.telephony.ServiceState; 33 import android.telephony.SubscriptionInfo; 34 import android.telephony.SubscriptionManager; 35 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 36 import android.telephony.TelephonyManager; 37 import android.text.TextUtils; 38 import android.util.Log; 39 import android.util.MathUtils; 40 41 import com.android.internal.annotations.VisibleForTesting; 42 import com.android.internal.telephony.PhoneConstants; 43 import com.android.internal.telephony.TelephonyIntents; 44 import com.android.settingslib.net.DataUsageController; 45 import com.android.systemui.DemoMode; 46 import com.android.systemui.R; 47 48 import java.io.FileDescriptor; 49 import java.io.PrintWriter; 50 import java.util.ArrayList; 51 import java.util.BitSet; 52 import java.util.Collections; 53 import java.util.Comparator; 54 import java.util.HashMap; 55 import java.util.List; 56 import java.util.Locale; 57 import java.util.Map; 58 59 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; 60 61 /** Platform implementation of the network controller. **/ 62 public class NetworkControllerImpl extends BroadcastReceiver 63 implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider { 64 // debug 65 static final String TAG = "NetworkController"; 66 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 67 // additional diagnostics, but not logspew 68 static final boolean CHATTY = Log.isLoggable(TAG + "Chat", Log.DEBUG); 69 70 private static final int EMERGENCY_NO_CONTROLLERS = 0; 71 private static final int EMERGENCY_FIRST_CONTROLLER = 100; 72 private static final int EMERGENCY_VOICE_CONTROLLER = 200; 73 private static final int EMERGENCY_NO_SUB = 300; 74 75 private final Context mContext; 76 private final TelephonyManager mPhone; 77 private final WifiManager mWifiManager; 78 private final ConnectivityManager mConnectivityManager; 79 private final SubscriptionManager mSubscriptionManager; 80 private final boolean mHasMobileDataFeature; 81 private final SubscriptionDefaults mSubDefaults; 82 private final DataSaverController mDataSaverController; 83 private Config mConfig; 84 85 // Subcontrollers. 86 @VisibleForTesting 87 final WifiSignalController mWifiSignalController; 88 89 @VisibleForTesting 90 final EthernetSignalController mEthernetSignalController; 91 92 @VisibleForTesting 93 final Map<Integer, MobileSignalController> mMobileSignalControllers = 94 new HashMap<Integer, MobileSignalController>(); 95 // When no SIMs are around at setup, and one is added later, it seems to default to the first 96 // SIM for most actions. This may be null if there aren't any SIMs around. 97 private MobileSignalController mDefaultSignalController; 98 private final AccessPointControllerImpl mAccessPoints; 99 private final DataUsageController mDataUsageController; 100 101 private boolean mInetCondition; // Used for Logging and demo. 102 103 // BitSets indicating which network transport types (e.g., TRANSPORT_WIFI, TRANSPORT_MOBILE) are 104 // connected and validated, respectively. 105 private final BitSet mConnectedTransports = new BitSet(); 106 private final BitSet mValidatedTransports = new BitSet(); 107 108 // States that don't belong to a subcontroller. 109 private boolean mAirplaneMode = false; 110 private boolean mHasNoSims; 111 private Locale mLocale = null; 112 // This list holds our ordering. 113 private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>(); 114 115 @VisibleForTesting 116 boolean mListening; 117 118 // The current user ID. 119 private int mCurrentUserId; 120 121 private OnSubscriptionsChangedListener mSubscriptionListener; 122 123 // Handler that all broadcasts are received on. 124 private final Handler mReceiverHandler; 125 // Handler that all callbacks are made on. 126 private final CallbackHandler mCallbackHandler; 127 128 private int mEmergencySource; 129 private boolean mIsEmergency; 130 131 @VisibleForTesting 132 ServiceState mLastServiceState; 133 private boolean mUserSetup; 134 135 /** 136 * Construct this controller object and register for updates. 137 */ 138 public NetworkControllerImpl(Context context, Looper bgLooper) { 139 this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE), 140 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE), 141 (WifiManager) context.getSystemService(Context.WIFI_SERVICE), 142 SubscriptionManager.from(context), Config.readConfig(context), bgLooper, 143 new CallbackHandler(), 144 new AccessPointControllerImpl(context, bgLooper), 145 new DataUsageController(context), 146 new SubscriptionDefaults()); 147 mReceiverHandler.post(mRegisterListeners); 148 } 149 150 @VisibleForTesting 151 NetworkControllerImpl(Context context, ConnectivityManager connectivityManager, 152 TelephonyManager telephonyManager, WifiManager wifiManager, 153 SubscriptionManager subManager, Config config, Looper bgLooper, 154 CallbackHandler callbackHandler, 155 AccessPointControllerImpl accessPointController, 156 DataUsageController dataUsageController, 157 SubscriptionDefaults defaultsHandler) { 158 mContext = context; 159 mConfig = config; 160 mReceiverHandler = new Handler(bgLooper); 161 mCallbackHandler = callbackHandler; 162 mDataSaverController = new DataSaverController(context); 163 164 mSubscriptionManager = subManager; 165 mSubDefaults = defaultsHandler; 166 mConnectivityManager = connectivityManager; 167 mHasMobileDataFeature = 168 mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); 169 170 // telephony 171 mPhone = telephonyManager; 172 173 // wifi 174 mWifiManager = wifiManager; 175 176 mLocale = mContext.getResources().getConfiguration().locale; 177 mAccessPoints = accessPointController; 178 mDataUsageController = dataUsageController; 179 mDataUsageController.setNetworkController(this); 180 // TODO: Find a way to move this into DataUsageController. 181 mDataUsageController.setCallback(new DataUsageController.Callback() { 182 @Override 183 public void onMobileDataEnabled(boolean enabled) { 184 mCallbackHandler.setMobileDataEnabled(enabled); 185 } 186 }); 187 mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature, 188 mCallbackHandler, this); 189 190 mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this); 191 192 // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it 193 updateAirplaneMode(true /* force callback */); 194 } 195 196 public DataSaverController getDataSaverController() { 197 return mDataSaverController; 198 } 199 200 private void registerListeners() { 201 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { 202 mobileSignalController.registerListener(); 203 } 204 if (mSubscriptionListener == null) { 205 mSubscriptionListener = new SubListener(); 206 } 207 mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener); 208 209 // broadcasts 210 IntentFilter filter = new IntentFilter(); 211 filter.addAction(WifiManager.RSSI_CHANGED_ACTION); 212 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 213 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 214 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 215 filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); 216 filter.addAction(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); 217 filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); 218 filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); 219 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 220 filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); 221 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 222 mContext.registerReceiver(this, filter, null, mReceiverHandler); 223 mListening = true; 224 225 updateMobileControllers(); 226 } 227 228 private void unregisterListeners() { 229 mListening = false; 230 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { 231 mobileSignalController.unregisterListener(); 232 } 233 mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener); 234 mContext.unregisterReceiver(this); 235 } 236 237 public int getConnectedWifiLevel() { 238 return mWifiSignalController.getState().level; 239 } 240 241 @Override 242 public AccessPointController getAccessPointController() { 243 return mAccessPoints; 244 } 245 246 @Override 247 public DataUsageController getMobileDataController() { 248 return mDataUsageController; 249 } 250 251 public void addEmergencyListener(EmergencyListener listener) { 252 mCallbackHandler.setListening(listener, true); 253 mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly()); 254 } 255 256 public void removeEmergencyListener(EmergencyListener listener) { 257 mCallbackHandler.setListening(listener, false); 258 } 259 260 public boolean hasMobileDataFeature() { 261 return mHasMobileDataFeature; 262 } 263 264 public boolean hasVoiceCallingFeature() { 265 return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE; 266 } 267 268 private MobileSignalController getDataController() { 269 int dataSubId = mSubDefaults.getDefaultDataSubId(); 270 if (!SubscriptionManager.isValidSubscriptionId(dataSubId)) { 271 if (DEBUG) Log.e(TAG, "No data sim selected"); 272 return mDefaultSignalController; 273 } 274 if (mMobileSignalControllers.containsKey(dataSubId)) { 275 return mMobileSignalControllers.get(dataSubId); 276 } 277 if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + dataSubId); 278 return mDefaultSignalController; 279 } 280 281 public String getMobileDataNetworkName() { 282 MobileSignalController controller = getDataController(); 283 return controller != null ? controller.getState().networkNameData : ""; 284 } 285 286 public boolean isEmergencyOnly() { 287 if (mMobileSignalControllers.size() == 0) { 288 // When there are no active subscriptions, determine emengency state from last 289 // broadcast. 290 mEmergencySource = EMERGENCY_NO_CONTROLLERS; 291 return mLastServiceState != null && mLastServiceState.isEmergencyOnly(); 292 } 293 int voiceSubId = mSubDefaults.getDefaultVoiceSubId(); 294 if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) { 295 for (MobileSignalController mobileSignalController : 296 mMobileSignalControllers.values()) { 297 if (!mobileSignalController.getState().isEmergency) { 298 mEmergencySource = EMERGENCY_FIRST_CONTROLLER 299 + mobileSignalController.mSubscriptionInfo.getSubscriptionId(); 300 if (DEBUG) Log.d(TAG, "Found emergency " + mobileSignalController.mTag); 301 return false; 302 } 303 } 304 } 305 if (mMobileSignalControllers.containsKey(voiceSubId)) { 306 mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId; 307 if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId); 308 return mMobileSignalControllers.get(voiceSubId).getState().isEmergency; 309 } 310 if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId); 311 mEmergencySource = EMERGENCY_NO_SUB + voiceSubId; 312 // Something is wrong, better assume we can't make calls... 313 return true; 314 } 315 316 /** 317 * Emergency status may have changed (triggered by MobileSignalController), 318 * so we should recheck and send out the state to listeners. 319 */ 320 void recalculateEmergency() { 321 mIsEmergency = isEmergencyOnly(); 322 mCallbackHandler.setEmergencyCallsOnly(mIsEmergency); 323 } 324 325 public void addSignalCallback(SignalCallback cb) { 326 cb.setSubs(mCurrentSubscriptions); 327 cb.setIsAirplaneMode(new IconState(mAirplaneMode, 328 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext)); 329 cb.setNoSims(mHasNoSims); 330 mWifiSignalController.notifyListeners(cb); 331 mEthernetSignalController.notifyListeners(cb); 332 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { 333 mobileSignalController.notifyListeners(cb); 334 } 335 mCallbackHandler.setListening(cb, true); 336 } 337 338 @Override 339 public void removeSignalCallback(SignalCallback cb) { 340 mCallbackHandler.setListening(cb, false); 341 } 342 343 @Override 344 public void setWifiEnabled(final boolean enabled) { 345 new AsyncTask<Void, Void, Void>() { 346 @Override 347 protected Void doInBackground(Void... args) { 348 // Disable tethering if enabling Wifi 349 final int wifiApState = mWifiManager.getWifiApState(); 350 if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) || 351 (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) { 352 mWifiManager.setWifiApEnabled(null, false); 353 } 354 355 mWifiManager.setWifiEnabled(enabled); 356 return null; 357 } 358 }.execute(); 359 } 360 361 @Override 362 public void onUserSwitched(int newUserId) { 363 mCurrentUserId = newUserId; 364 mAccessPoints.onUserSwitched(newUserId); 365 updateConnectivity(); 366 } 367 368 @Override 369 public void onReceive(Context context, Intent intent) { 370 if (CHATTY) { 371 Log.d(TAG, "onReceive: intent=" + intent); 372 } 373 final String action = intent.getAction(); 374 if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) || 375 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) { 376 updateConnectivity(); 377 } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 378 refreshLocale(); 379 updateAirplaneMode(false); 380 } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED)) { 381 // We are using different subs now, we might be able to make calls. 382 recalculateEmergency(); 383 } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) { 384 // Notify every MobileSignalController so they can know whether they are the 385 // data sim or not. 386 for (MobileSignalController controller : mMobileSignalControllers.values()) { 387 controller.handleBroadcast(intent); 388 } 389 } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { 390 // Might have different subscriptions now. 391 updateMobileControllers(); 392 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) { 393 mLastServiceState = ServiceState.newFromBundle(intent.getExtras()); 394 if (mMobileSignalControllers.size() == 0) { 395 // If none of the subscriptions are active, we might need to recalculate 396 // emergency state. 397 recalculateEmergency(); 398 } 399 } else { 400 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, 401 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 402 if (SubscriptionManager.isValidSubscriptionId(subId)) { 403 if (mMobileSignalControllers.containsKey(subId)) { 404 mMobileSignalControllers.get(subId).handleBroadcast(intent); 405 } else { 406 // Can't find this subscription... We must be out of date. 407 updateMobileControllers(); 408 } 409 } else { 410 // No sub id, must be for the wifi. 411 mWifiSignalController.handleBroadcast(intent); 412 } 413 } 414 } 415 416 public void onConfigurationChanged() { 417 mConfig = Config.readConfig(mContext); 418 mReceiverHandler.post(new Runnable() { 419 @Override 420 public void run() { 421 handleConfigurationChanged(); 422 } 423 }); 424 } 425 426 @VisibleForTesting 427 void handleConfigurationChanged() { 428 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { 429 mobileSignalController.setConfiguration(mConfig); 430 } 431 refreshLocale(); 432 } 433 434 private void updateMobileControllers() { 435 if (!mListening) { 436 return; 437 } 438 doUpdateMobileControllers(); 439 } 440 441 @VisibleForTesting 442 void doUpdateMobileControllers() { 443 List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList(); 444 if (subscriptions == null) { 445 subscriptions = Collections.emptyList(); 446 } 447 // If there have been no relevant changes to any of the subscriptions, we can leave as is. 448 if (hasCorrectMobileControllers(subscriptions)) { 449 // Even if the controllers are correct, make sure we have the right no sims state. 450 // Such as on boot, don't need any controllers, because there are no sims, 451 // but we still need to update the no sim state. 452 updateNoSims(); 453 return; 454 } 455 setCurrentSubscriptions(subscriptions); 456 updateNoSims(); 457 recalculateEmergency(); 458 } 459 460 @VisibleForTesting 461 protected void updateNoSims() { 462 boolean hasNoSims = mHasMobileDataFeature && mMobileSignalControllers.size() == 0; 463 if (hasNoSims != mHasNoSims) { 464 mHasNoSims = hasNoSims; 465 mCallbackHandler.setNoSims(mHasNoSims); 466 } 467 } 468 469 @VisibleForTesting 470 void setCurrentSubscriptions(List<SubscriptionInfo> subscriptions) { 471 Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() { 472 @Override 473 public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) { 474 return lhs.getSimSlotIndex() == rhs.getSimSlotIndex() 475 ? lhs.getSubscriptionId() - rhs.getSubscriptionId() 476 : lhs.getSimSlotIndex() - rhs.getSimSlotIndex(); 477 } 478 }); 479 mCurrentSubscriptions = subscriptions; 480 481 HashMap<Integer, MobileSignalController> cachedControllers = 482 new HashMap<Integer, MobileSignalController>(mMobileSignalControllers); 483 mMobileSignalControllers.clear(); 484 final int num = subscriptions.size(); 485 for (int i = 0; i < num; i++) { 486 int subId = subscriptions.get(i).getSubscriptionId(); 487 // If we have a copy of this controller already reuse it, otherwise make a new one. 488 if (cachedControllers.containsKey(subId)) { 489 mMobileSignalControllers.put(subId, cachedControllers.remove(subId)); 490 } else { 491 MobileSignalController controller = new MobileSignalController(mContext, mConfig, 492 mHasMobileDataFeature, mPhone, mCallbackHandler, 493 this, subscriptions.get(i), mSubDefaults, mReceiverHandler.getLooper()); 494 controller.setUserSetupComplete(mUserSetup); 495 mMobileSignalControllers.put(subId, controller); 496 if (subscriptions.get(i).getSimSlotIndex() == 0) { 497 mDefaultSignalController = controller; 498 } 499 if (mListening) { 500 controller.registerListener(); 501 } 502 } 503 } 504 if (mListening) { 505 for (Integer key : cachedControllers.keySet()) { 506 if (cachedControllers.get(key) == mDefaultSignalController) { 507 mDefaultSignalController = null; 508 } 509 cachedControllers.get(key).unregisterListener(); 510 } 511 } 512 mCallbackHandler.setSubs(subscriptions); 513 notifyAllListeners(); 514 515 // There may be new MobileSignalControllers around, make sure they get the current 516 // inet condition and airplane mode. 517 pushConnectivityToSignals(); 518 updateAirplaneMode(true /* force */); 519 } 520 521 public void setUserSetupComplete(final boolean userSetup) { 522 mReceiverHandler.post(new Runnable() { 523 @Override 524 public void run() { 525 handleSetUserSetupComplete(userSetup); 526 } 527 }); 528 } 529 530 @VisibleForTesting 531 void handleSetUserSetupComplete(boolean userSetup) { 532 mUserSetup = userSetup; 533 for (MobileSignalController controller : mMobileSignalControllers.values()) { 534 controller.setUserSetupComplete(mUserSetup); 535 } 536 } 537 538 @VisibleForTesting 539 boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) { 540 if (allSubscriptions.size() != mMobileSignalControllers.size()) { 541 return false; 542 } 543 for (SubscriptionInfo info : allSubscriptions) { 544 if (!mMobileSignalControllers.containsKey(info.getSubscriptionId())) { 545 return false; 546 } 547 } 548 return true; 549 } 550 551 private void updateAirplaneMode(boolean force) { 552 boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(), 553 Settings.Global.AIRPLANE_MODE_ON, 0) == 1); 554 if (airplaneMode != mAirplaneMode || force) { 555 mAirplaneMode = airplaneMode; 556 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { 557 mobileSignalController.setAirplaneMode(mAirplaneMode); 558 } 559 notifyListeners(); 560 } 561 } 562 563 private void refreshLocale() { 564 Locale current = mContext.getResources().getConfiguration().locale; 565 if (!current.equals(mLocale)) { 566 mLocale = current; 567 notifyAllListeners(); 568 } 569 } 570 571 /** 572 * Forces update of all callbacks on both SignalClusters and 573 * NetworkSignalChangedCallbacks. 574 */ 575 private void notifyAllListeners() { 576 notifyListeners(); 577 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { 578 mobileSignalController.notifyListeners(); 579 } 580 mWifiSignalController.notifyListeners(); 581 mEthernetSignalController.notifyListeners(); 582 } 583 584 /** 585 * Notifies listeners of changes in state of to the NetworkController, but 586 * does not notify for any info on SignalControllers, for that call 587 * notifyAllListeners. 588 */ 589 private void notifyListeners() { 590 mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode, 591 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext)); 592 mCallbackHandler.setNoSims(mHasNoSims); 593 } 594 595 /** 596 * Update the Inet conditions and what network we are connected to. 597 */ 598 private void updateConnectivity() { 599 mConnectedTransports.clear(); 600 mValidatedTransports.clear(); 601 for (NetworkCapabilities nc : 602 mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) { 603 for (int transportType : nc.getTransportTypes()) { 604 mConnectedTransports.set(transportType); 605 if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) { 606 mValidatedTransports.set(transportType); 607 } 608 } 609 } 610 611 if (CHATTY) { 612 Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports); 613 Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports); 614 } 615 616 mInetCondition = !mValidatedTransports.isEmpty(); 617 618 pushConnectivityToSignals(); 619 } 620 621 /** 622 * Pushes the current connectivity state to all SignalControllers. 623 */ 624 private void pushConnectivityToSignals() { 625 // We want to update all the icons, all at once, for any condition change 626 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { 627 mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 628 } 629 mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 630 mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 631 } 632 633 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 634 pw.println("NetworkController state:"); 635 636 pw.println(" - telephony ------"); 637 pw.print(" hasVoiceCallingFeature()="); 638 pw.println(hasVoiceCallingFeature()); 639 640 pw.println(" - connectivity ------"); 641 pw.print(" mConnectedTransports="); 642 pw.println(mConnectedTransports); 643 pw.print(" mValidatedTransports="); 644 pw.println(mValidatedTransports); 645 pw.print(" mInetCondition="); 646 pw.println(mInetCondition); 647 pw.print(" mAirplaneMode="); 648 pw.println(mAirplaneMode); 649 pw.print(" mLocale="); 650 pw.println(mLocale); 651 pw.print(" mLastServiceState="); 652 pw.println(mLastServiceState); 653 pw.print(" mIsEmergency="); 654 pw.println(mIsEmergency); 655 pw.print(" mEmergencySource="); 656 pw.println(emergencyToString(mEmergencySource)); 657 658 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { 659 mobileSignalController.dump(pw); 660 } 661 mWifiSignalController.dump(pw); 662 663 mEthernetSignalController.dump(pw); 664 665 mAccessPoints.dump(pw); 666 } 667 668 private static final String emergencyToString(int emergencySource) { 669 if (emergencySource > EMERGENCY_NO_SUB) { 670 return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")"; 671 } else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) { 672 return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")"; 673 } else if (emergencySource > EMERGENCY_FIRST_CONTROLLER) { 674 return "FIRST_CONTROLLER(" + (emergencySource - EMERGENCY_FIRST_CONTROLLER) + ")"; 675 } else if (emergencySource == EMERGENCY_NO_CONTROLLERS) { 676 return "NO_CONTROLLERS"; 677 } 678 return "UNKNOWN_SOURCE"; 679 } 680 681 private boolean mDemoMode; 682 private boolean mDemoInetCondition; 683 private WifiSignalController.WifiState mDemoWifiState; 684 685 @Override 686 public void dispatchDemoCommand(String command, Bundle args) { 687 if (!mDemoMode && command.equals(COMMAND_ENTER)) { 688 if (DEBUG) Log.d(TAG, "Entering demo mode"); 689 unregisterListeners(); 690 mDemoMode = true; 691 mDemoInetCondition = mInetCondition; 692 mDemoWifiState = mWifiSignalController.getState(); 693 } else if (mDemoMode && command.equals(COMMAND_EXIT)) { 694 if (DEBUG) Log.d(TAG, "Exiting demo mode"); 695 mDemoMode = false; 696 // Update what MobileSignalControllers, because they may change 697 // to set the number of sim slots. 698 updateMobileControllers(); 699 for (MobileSignalController controller : mMobileSignalControllers.values()) { 700 controller.resetLastState(); 701 } 702 mWifiSignalController.resetLastState(); 703 mReceiverHandler.post(mRegisterListeners); 704 notifyAllListeners(); 705 } else if (mDemoMode && command.equals(COMMAND_NETWORK)) { 706 String airplane = args.getString("airplane"); 707 if (airplane != null) { 708 boolean show = airplane.equals("show"); 709 mCallbackHandler.setIsAirplaneMode(new IconState(show, 710 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, 711 mContext)); 712 } 713 String fully = args.getString("fully"); 714 if (fully != null) { 715 mDemoInetCondition = Boolean.parseBoolean(fully); 716 BitSet connected = new BitSet(); 717 718 if (mDemoInetCondition) { 719 connected.set(mWifiSignalController.mTransportType); 720 } 721 mWifiSignalController.updateConnectivity(connected, connected); 722 for (MobileSignalController controller : mMobileSignalControllers.values()) { 723 if (mDemoInetCondition) { 724 connected.set(controller.mTransportType); 725 } 726 controller.updateConnectivity(connected, connected); 727 } 728 } 729 String wifi = args.getString("wifi"); 730 if (wifi != null) { 731 boolean show = wifi.equals("show"); 732 String level = args.getString("level"); 733 if (level != null) { 734 mDemoWifiState.level = level.equals("null") ? -1 735 : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1); 736 mDemoWifiState.connected = mDemoWifiState.level >= 0; 737 } 738 mDemoWifiState.enabled = show; 739 mWifiSignalController.notifyListeners(); 740 } 741 String sims = args.getString("sims"); 742 if (sims != null) { 743 int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8); 744 List<SubscriptionInfo> subs = new ArrayList<>(); 745 if (num != mMobileSignalControllers.size()) { 746 mMobileSignalControllers.clear(); 747 int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); 748 for (int i = start /* get out of normal index range */; i < start + num; i++) { 749 subs.add(addSignalController(i, i)); 750 } 751 mCallbackHandler.setSubs(subs); 752 } 753 } 754 String nosim = args.getString("nosim"); 755 if (nosim != null) { 756 mHasNoSims = nosim.equals("show"); 757 mCallbackHandler.setNoSims(mHasNoSims); 758 } 759 String mobile = args.getString("mobile"); 760 if (mobile != null) { 761 boolean show = mobile.equals("show"); 762 String datatype = args.getString("datatype"); 763 String slotString = args.getString("slot"); 764 int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString); 765 slot = MathUtils.constrain(slot, 0, 8); 766 // Ensure we have enough sim slots 767 List<SubscriptionInfo> subs = new ArrayList<>(); 768 while (mMobileSignalControllers.size() <= slot) { 769 int nextSlot = mMobileSignalControllers.size(); 770 subs.add(addSignalController(nextSlot, nextSlot)); 771 } 772 if (!subs.isEmpty()) { 773 mCallbackHandler.setSubs(subs); 774 } 775 // Hack to index linearly for easy use. 776 MobileSignalController controller = mMobileSignalControllers 777 .values().toArray(new MobileSignalController[0])[slot]; 778 controller.getState().dataSim = datatype != null; 779 if (datatype != null) { 780 controller.getState().iconGroup = 781 datatype.equals("1x") ? TelephonyIcons.ONE_X : 782 datatype.equals("3g") ? TelephonyIcons.THREE_G : 783 datatype.equals("4g") ? TelephonyIcons.FOUR_G : 784 datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS : 785 datatype.equals("e") ? TelephonyIcons.E : 786 datatype.equals("g") ? TelephonyIcons.G : 787 datatype.equals("h") ? TelephonyIcons.H : 788 datatype.equals("lte") ? TelephonyIcons.LTE : 789 datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS : 790 datatype.equals("roam") ? TelephonyIcons.ROAMING : 791 TelephonyIcons.UNKNOWN; 792 } 793 int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH; 794 String level = args.getString("level"); 795 if (level != null) { 796 controller.getState().level = level.equals("null") ? -1 797 : Math.min(Integer.parseInt(level), icons[0].length - 1); 798 controller.getState().connected = controller.getState().level >= 0; 799 } 800 controller.getState().enabled = show; 801 controller.notifyListeners(); 802 } 803 String carrierNetworkChange = args.getString("carriernetworkchange"); 804 if (carrierNetworkChange != null) { 805 boolean show = carrierNetworkChange.equals("show"); 806 for (MobileSignalController controller : mMobileSignalControllers.values()) { 807 controller.setCarrierNetworkChangeMode(show); 808 } 809 } 810 } 811 } 812 813 private SubscriptionInfo addSignalController(int id, int simSlotIndex) { 814 SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0, 815 null, 0, 0, ""); 816 mMobileSignalControllers.put(id, new MobileSignalController(mContext, 817 mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info, 818 mSubDefaults, mReceiverHandler.getLooper())); 819 return info; 820 } 821 822 private class SubListener extends OnSubscriptionsChangedListener { 823 @Override 824 public void onSubscriptionsChanged() { 825 updateMobileControllers(); 826 } 827 } 828 829 /** 830 * Used to register listeners from the BG Looper, this way the PhoneStateListeners that 831 * get created will also run on the BG Looper. 832 */ 833 private final Runnable mRegisterListeners = new Runnable() { 834 @Override 835 public void run() { 836 registerListeners(); 837 } 838 }; 839 840 public static class SubscriptionDefaults { 841 public int getDefaultVoiceSubId() { 842 return SubscriptionManager.getDefaultVoiceSubscriptionId(); 843 } 844 845 public int getDefaultDataSubId() { 846 return SubscriptionManager.getDefaultDataSubscriptionId(); 847 } 848 } 849 850 @VisibleForTesting 851 static class Config { 852 boolean showAtLeast3G = false; 853 boolean alwaysShowCdmaRssi = false; 854 boolean show4gForLte = false; 855 boolean hideLtePlus = false; 856 boolean hspaDataDistinguishable; 857 858 static Config readConfig(Context context) { 859 Config config = new Config(); 860 Resources res = context.getResources(); 861 862 config.showAtLeast3G = res.getBoolean(R.bool.config_showMin3G); 863 config.alwaysShowCdmaRssi = 864 res.getBoolean(com.android.internal.R.bool.config_alwaysUseCdmaRssi); 865 config.show4gForLte = res.getBoolean(R.bool.config_show4GForLTE); 866 config.hspaDataDistinguishable = 867 res.getBoolean(R.bool.config_hspa_data_distinguishable); 868 config.hideLtePlus = res.getBoolean(R.bool.config_hideLtePlus); 869 return config; 870 } 871 } 872 } 873