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