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