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.connectivity; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; 20 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 21 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 22 23 import android.annotation.Nullable; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.res.Configuration; 29 import android.net.ConnectivityManager; 30 import android.net.ConnectivityManager.NetworkCallback; 31 import android.net.Network; 32 import android.net.NetworkCapabilities; 33 import android.net.wifi.ScanResult; 34 import android.net.wifi.WifiManager; 35 import android.os.AsyncTask; 36 import android.os.Bundle; 37 import android.os.Handler; 38 import android.os.HandlerExecutor; 39 import android.os.Looper; 40 import android.provider.Settings; 41 import android.telephony.CarrierConfigManager; 42 import android.telephony.CellSignalStrength; 43 import android.telephony.ServiceState; 44 import android.telephony.SubscriptionInfo; 45 import android.telephony.SubscriptionManager; 46 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 47 import android.telephony.TelephonyCallback; 48 import android.telephony.TelephonyManager; 49 import android.text.TextUtils; 50 import android.util.Log; 51 import android.util.MathUtils; 52 import android.util.SparseArray; 53 54 import androidx.annotation.NonNull; 55 56 import com.android.internal.annotations.GuardedBy; 57 import com.android.internal.annotations.VisibleForTesting; 58 import com.android.settingslib.Utils; 59 import com.android.settingslib.mobile.MobileMappings.Config; 60 import com.android.settingslib.mobile.MobileStatusTracker.SubscriptionDefaults; 61 import com.android.settingslib.mobile.TelephonyIcons; 62 import com.android.settingslib.net.DataUsageController; 63 import com.android.systemui.Dumpable; 64 import com.android.systemui.broadcast.BroadcastDispatcher; 65 import com.android.systemui.dagger.SysUISingleton; 66 import com.android.systemui.dagger.qualifiers.Background; 67 import com.android.systemui.dagger.qualifiers.Main; 68 import com.android.systemui.demomode.DemoMode; 69 import com.android.systemui.demomode.DemoModeController; 70 import com.android.systemui.dump.DumpManager; 71 import com.android.systemui.log.LogBuffer; 72 import com.android.systemui.log.core.LogLevel; 73 import com.android.systemui.log.dagger.StatusBarNetworkControllerLog; 74 import com.android.systemui.qs.tiles.dialog.InternetDialogManager; 75 import com.android.systemui.res.R; 76 import com.android.systemui.settings.UserTracker; 77 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags; 78 import com.android.systemui.statusbar.policy.ConfigurationController; 79 import com.android.systemui.statusbar.policy.DataSaverController; 80 import com.android.systemui.statusbar.policy.DataSaverControllerImpl; 81 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 82 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; 83 import com.android.systemui.telephony.TelephonyListenerManager; 84 import com.android.systemui.util.CarrierConfigTracker; 85 86 import dalvik.annotation.optimization.NeverCompile; 87 88 import kotlin.Unit; 89 90 import java.io.PrintWriter; 91 import java.text.SimpleDateFormat; 92 import java.util.ArrayList; 93 import java.util.Arrays; 94 import java.util.BitSet; 95 import java.util.Collections; 96 import java.util.Comparator; 97 import java.util.List; 98 import java.util.Locale; 99 import java.util.concurrent.Executor; 100 import java.util.stream.Collectors; 101 102 import javax.inject.Inject; 103 104 /** Platform implementation of the network controller. **/ 105 @SysUISingleton 106 public class NetworkControllerImpl extends BroadcastReceiver 107 implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider, Dumpable { 108 // debug 109 static final String TAG = "NetworkController"; 110 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 111 // additional diagnostics, but not logspew 112 static final boolean CHATTY = Log.isLoggable(TAG + "Chat", Log.DEBUG); 113 114 private static final int EMERGENCY_NO_CONTROLLERS = 0; 115 private static final int EMERGENCY_FIRST_CONTROLLER = 100; 116 private static final int EMERGENCY_VOICE_CONTROLLER = 200; 117 private static final int EMERGENCY_NO_SUB = 300; 118 private static final int EMERGENCY_ASSUMED_VOICE_CONTROLLER = 400; 119 private static final int HISTORY_SIZE = 16; 120 private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); 121 122 private final Context mContext; 123 private final TelephonyManager mPhone; 124 private final TelephonyListenerManager mTelephonyListenerManager; 125 private final WifiManager mWifiManager; 126 private final ConnectivityManager mConnectivityManager; 127 private final SubscriptionManager mSubscriptionManager; 128 private final boolean mHasMobileDataFeature; 129 private final SubscriptionDefaults mSubDefaults; 130 private final DataSaverController mDataSaverController; 131 private final UserTracker mUserTracker; 132 private final BroadcastDispatcher mBroadcastDispatcher; 133 private final DemoModeController mDemoModeController; 134 private final Object mLock = new Object(); 135 private Config mConfig; 136 private final CarrierConfigTracker mCarrierConfigTracker; 137 private final DumpManager mDumpManager; 138 private final LogBuffer mLogBuffer; 139 private final MobileSignalControllerFactory mMobileFactory; 140 141 private TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener; 142 private int mActiveMobileDataSubscription = INVALID_SUBSCRIPTION_ID; 143 144 // Subcontrollers. 145 @VisibleForTesting 146 final WifiSignalController mWifiSignalController; 147 148 @VisibleForTesting 149 final EthernetSignalController mEthernetSignalController; 150 151 @VisibleForTesting 152 final SparseArray<MobileSignalController> mMobileSignalControllers = new SparseArray<>(); 153 // When no SIMs are around at setup, and one is added later, it seems to default to the first 154 // SIM for most actions. This may be null if there aren't any SIMs around. 155 private MobileSignalController mDefaultSignalController; 156 private final AccessPointControllerImpl mAccessPoints; 157 private final DataUsageController mDataUsageController; 158 159 private boolean mInetCondition; // Used for Logging and demo. 160 161 // BitSets indicating which network transport types (e.g., TRANSPORT_WIFI, TRANSPORT_MOBILE) are 162 // connected and validated, respectively. 163 private final BitSet mConnectedTransports = new BitSet(); 164 private final BitSet mValidatedTransports = new BitSet(); 165 166 // States that don't belong to a subcontroller. 167 private boolean mAirplaneMode = false; 168 private boolean mHasNoSubs; 169 private boolean mNoDefaultNetwork = false; 170 private boolean mNoNetworksAvailable = true; 171 private Locale mLocale = null; 172 // This list holds our ordering. 173 private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>(); 174 175 // Save the previous HISTORY_SIZE states for logging. 176 private final String[] mHistory = new String[HISTORY_SIZE]; 177 // Where to copy the next state into. 178 private int mHistoryIndex; 179 180 @VisibleForTesting 181 boolean mListening; 182 183 // The current user ID. 184 private int mCurrentUserId; 185 186 private OnSubscriptionsChangedListener mSubscriptionListener; 187 private NetworkCapabilities mLastDefaultNetworkCapabilities; 188 // Handler that all broadcasts are received on. 189 private final Handler mReceiverHandler; 190 private final Looper mBgLooper; 191 private final Executor mBgExecutor; 192 // Handler that all callbacks are made on. 193 private final CallbackHandler mCallbackHandler; 194 private final StatusBarPipelineFlags mStatusBarPipelineFlags; 195 196 private int mEmergencySource; 197 private boolean mIsEmergency; 198 199 @VisibleForTesting 200 ServiceState mLastServiceState; 201 private boolean mUserSetup; 202 private boolean mSimDetected; 203 private boolean mForceCellularValidated; 204 private InternetDialogManager mInternetDialogManager; 205 private Handler mMainHandler; 206 207 private ConfigurationController.ConfigurationListener mConfigurationListener = 208 new ConfigurationController.ConfigurationListener() { 209 @Override 210 public void onConfigChanged(Configuration newConfig) { 211 mConfig = Config.readConfig(mContext); 212 mReceiverHandler.post(() -> handleConfigurationChanged()); 213 } 214 }; 215 216 private final UserTracker.Callback mUserChangedCallback = 217 new UserTracker.Callback() { 218 @Override 219 public void onUserChanged(int newUser, @NonNull Context userContext) { 220 NetworkControllerImpl.this.onUserSwitched(newUser); 221 } 222 }; 223 224 /** 225 * Construct this controller object and register for updates. 226 */ 227 @Inject NetworkControllerImpl( Context context, @Background Looper bgLooper, @Background Executor bgExecutor, SubscriptionManager subscriptionManager, CallbackHandler callbackHandler, DeviceProvisionedController deviceProvisionedController, BroadcastDispatcher broadcastDispatcher, UserTracker userTracker, ConnectivityManager connectivityManager, TelephonyManager telephonyManager, TelephonyListenerManager telephonyListenerManager, @Nullable WifiManager wifiManager, AccessPointControllerImpl accessPointController, StatusBarPipelineFlags statusBarPipelineFlags, DemoModeController demoModeController, CarrierConfigTracker carrierConfigTracker, WifiStatusTrackerFactory trackerFactory, MobileSignalControllerFactory mobileFactory, @Main Handler handler, InternetDialogManager internetDialogManager, DumpManager dumpManager, @StatusBarNetworkControllerLog LogBuffer logBuffer)228 public NetworkControllerImpl( 229 Context context, 230 @Background Looper bgLooper, 231 @Background Executor bgExecutor, 232 SubscriptionManager subscriptionManager, 233 CallbackHandler callbackHandler, 234 DeviceProvisionedController deviceProvisionedController, 235 BroadcastDispatcher broadcastDispatcher, 236 UserTracker userTracker, 237 ConnectivityManager connectivityManager, 238 TelephonyManager telephonyManager, 239 TelephonyListenerManager telephonyListenerManager, 240 @Nullable WifiManager wifiManager, 241 AccessPointControllerImpl accessPointController, 242 StatusBarPipelineFlags statusBarPipelineFlags, 243 DemoModeController demoModeController, 244 CarrierConfigTracker carrierConfigTracker, 245 WifiStatusTrackerFactory trackerFactory, 246 MobileSignalControllerFactory mobileFactory, 247 @Main Handler handler, 248 InternetDialogManager internetDialogManager, 249 DumpManager dumpManager, 250 @StatusBarNetworkControllerLog LogBuffer logBuffer) { 251 this(context, connectivityManager, 252 telephonyManager, 253 telephonyListenerManager, 254 wifiManager, 255 subscriptionManager, 256 Config.readConfig(context), 257 bgLooper, 258 bgExecutor, 259 callbackHandler, 260 accessPointController, 261 statusBarPipelineFlags, 262 new DataUsageController(context), 263 new SubscriptionDefaults(), 264 deviceProvisionedController, 265 broadcastDispatcher, 266 userTracker, 267 demoModeController, 268 carrierConfigTracker, 269 trackerFactory, 270 mobileFactory, 271 handler, 272 dumpManager, 273 logBuffer); 274 mReceiverHandler.post(mRegisterListeners); 275 mInternetDialogManager = internetDialogManager; 276 } 277 278 @VisibleForTesting NetworkControllerImpl(Context context, ConnectivityManager connectivityManager, TelephonyManager telephonyManager, TelephonyListenerManager telephonyListenerManager, WifiManager wifiManager, SubscriptionManager subManager, Config config, Looper bgLooper, Executor bgExecutor, CallbackHandler callbackHandler, AccessPointControllerImpl accessPointController, StatusBarPipelineFlags statusBarPipelineFlags, DataUsageController dataUsageController, SubscriptionDefaults defaultsHandler, DeviceProvisionedController deviceProvisionedController, BroadcastDispatcher broadcastDispatcher, UserTracker userTracker, DemoModeController demoModeController, CarrierConfigTracker carrierConfigTracker, WifiStatusTrackerFactory trackerFactory, MobileSignalControllerFactory mobileFactory, @Main Handler handler, DumpManager dumpManager, LogBuffer logBuffer )279 NetworkControllerImpl(Context context, ConnectivityManager connectivityManager, 280 TelephonyManager telephonyManager, 281 TelephonyListenerManager telephonyListenerManager, 282 WifiManager wifiManager, 283 SubscriptionManager subManager, 284 Config config, 285 Looper bgLooper, 286 Executor bgExecutor, 287 CallbackHandler callbackHandler, 288 AccessPointControllerImpl accessPointController, 289 StatusBarPipelineFlags statusBarPipelineFlags, 290 DataUsageController dataUsageController, 291 SubscriptionDefaults defaultsHandler, 292 DeviceProvisionedController deviceProvisionedController, 293 BroadcastDispatcher broadcastDispatcher, 294 UserTracker userTracker, 295 DemoModeController demoModeController, 296 CarrierConfigTracker carrierConfigTracker, 297 WifiStatusTrackerFactory trackerFactory, 298 MobileSignalControllerFactory mobileFactory, 299 @Main Handler handler, 300 DumpManager dumpManager, 301 LogBuffer logBuffer 302 ) { 303 mContext = context; 304 mTelephonyListenerManager = telephonyListenerManager; 305 mConfig = config; 306 mMainHandler = handler; 307 mReceiverHandler = new Handler(bgLooper); 308 mBgLooper = bgLooper; 309 mBgExecutor = bgExecutor; 310 mCallbackHandler = callbackHandler; 311 mStatusBarPipelineFlags = statusBarPipelineFlags; 312 mDataSaverController = new DataSaverControllerImpl(context); 313 mBroadcastDispatcher = broadcastDispatcher; 314 mMobileFactory = mobileFactory; 315 316 mSubscriptionManager = subManager; 317 mSubDefaults = defaultsHandler; 318 mConnectivityManager = connectivityManager; 319 mHasMobileDataFeature = telephonyManager.isDataCapable(); 320 mDemoModeController = demoModeController; 321 mCarrierConfigTracker = carrierConfigTracker; 322 mDumpManager = dumpManager; 323 mLogBuffer = logBuffer; 324 325 // telephony 326 mPhone = telephonyManager; 327 328 // wifi 329 mWifiManager = wifiManager; 330 331 mLocale = mContext.getResources().getConfiguration().locale; 332 mAccessPoints = accessPointController; 333 mDataUsageController = dataUsageController; 334 mDataUsageController.setNetworkController(this); 335 // TODO: Find a way to move this into DataUsageController. 336 mDataUsageController.setCallback(new DataUsageController.Callback() { 337 @Override 338 public void onMobileDataEnabled(boolean enabled) { 339 mCallbackHandler.setMobileDataEnabled(enabled); 340 notifyControllersMobileDataChanged(); 341 } 342 }); 343 344 mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature, 345 mCallbackHandler, this, mWifiManager, trackerFactory, 346 mReceiverHandler); 347 348 mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this); 349 350 // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it 351 updateAirplaneMode(true /* force callback */); 352 mUserTracker = userTracker; 353 mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(mMainHandler)); 354 355 deviceProvisionedController.addCallback(new DeviceProvisionedListener() { 356 @Override 357 public void onUserSetupChanged() { 358 setUserSetupComplete(deviceProvisionedController.isCurrentUserSetup()); 359 } 360 }); 361 // Get initial user setup state 362 setUserSetupComplete(deviceProvisionedController.isCurrentUserSetup()); 363 364 WifiManager.ScanResultsCallback scanResultsCallback = 365 new WifiManager.ScanResultsCallback() { 366 @Override 367 public void onScanResultsAvailable() { 368 mNoNetworksAvailable = true; 369 for (ScanResult scanResult : mWifiManager.getScanResults()) { 370 if (!scanResult.SSID.equals(mWifiSignalController.getState().ssid)) { 371 mNoNetworksAvailable = false; 372 break; 373 } 374 } 375 // Only update the network availability if there is no default network. 376 if (mNoDefaultNetwork) { 377 mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition, 378 mNoNetworksAvailable); 379 } 380 } 381 }; 382 383 if (mWifiManager != null) { 384 mWifiManager.registerScanResultsCallback(mReceiverHandler::post, scanResultsCallback); 385 } 386 387 NetworkCallback callback = 388 new NetworkCallback(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO){ 389 private Network mLastNetwork; 390 private NetworkCapabilities mLastNetworkCapabilities; 391 392 @Override 393 public void onLost(Network network) { 394 mLastNetwork = null; 395 mLastNetworkCapabilities = null; 396 mLastDefaultNetworkCapabilities = null; 397 String callback = new StringBuilder() 398 .append(SSDF.format(System.currentTimeMillis())).append(",") 399 .append("onLost: ") 400 .append("network=").append(network) 401 .toString(); 402 recordLastNetworkCallback(callback); 403 updateConnectivity(); 404 } 405 406 @Override 407 public void onCapabilitiesChanged( 408 Network network, NetworkCapabilities networkCapabilities) { 409 boolean lastValidated = (mLastNetworkCapabilities != null) 410 && mLastNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED); 411 boolean validated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED); 412 413 // This callback is invoked a lot (i.e. when RSSI changes), so avoid updating 414 // icons when connectivity state has remained the same. 415 if (network.equals(mLastNetwork) && validated == lastValidated) { 416 // Should not rely on getTransportTypes() returning the same order of transport 417 // types. So sort the array before comparing. 418 int[] newTypes = getProcessedTransportTypes(networkCapabilities); 419 Arrays.sort(newTypes); 420 421 int[] lastTypes = (mLastNetworkCapabilities != null) 422 ? getProcessedTransportTypes(mLastNetworkCapabilities) : null; 423 if (lastTypes != null) Arrays.sort(lastTypes); 424 425 if (Arrays.equals(newTypes, lastTypes)) { 426 return; 427 } 428 } 429 mLastNetwork = network; 430 mLastNetworkCapabilities = networkCapabilities; 431 mLastDefaultNetworkCapabilities = networkCapabilities; 432 String callback = new StringBuilder() 433 .append(SSDF.format(System.currentTimeMillis())).append(",") 434 .append("onCapabilitiesChanged: ") 435 .append("network=").append(network).append(",") 436 .append("networkCapabilities=").append(networkCapabilities) 437 .toString(); 438 recordLastNetworkCallback(callback); 439 updateConnectivity(); 440 } 441 }; 442 // Even though this callback runs on the receiver handler thread which also processes the 443 // CONNECTIVITY_ACTION broadcasts, the broadcast and callback might come in at different 444 // times. This is safe since updateConnectivity() builds the list of transports from 445 // scratch. 446 // TODO: Move off of the deprecated CONNECTIVITY_ACTION broadcast and rely on callbacks 447 // exclusively for status bar icons. 448 mConnectivityManager.registerDefaultNetworkCallback(callback, mReceiverHandler); 449 // Run the listener on our bg looper 450 mPhoneStateListener = subId -> { 451 mBgExecutor.execute(() -> { 452 // For data switching from A to B, we assume B is validated for up to 2 seconds if: 453 // 1) A and B are in the same subscription group e.g. CBRS data switch. And 454 // 2) A was validated before the switch. 455 // This is to provide smooth transition for UI without showing cross during data 456 // switch. 457 if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) { 458 if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true."); 459 mForceCellularValidated = true; 460 mReceiverHandler.removeCallbacks(mClearForceValidated); 461 mReceiverHandler.postDelayed(mClearForceValidated, 2000); 462 } 463 mActiveMobileDataSubscription = subId; 464 doUpdateMobileControllers(); 465 }); 466 }; 467 468 // TODO(b/336357360): Until we can remove this class entirely, disable its handling of ALL 469 // demo mode commands, due to the fact that the mobile command handler has an infinite 470 // loop bug if you use any slot other than 1. 471 // mDemoModeController.addCallback(this); 472 473 mDumpManager.registerNormalDumpable(TAG, this); 474 } 475 476 private final Runnable mClearForceValidated = () -> { 477 if (DEBUG) Log.d(TAG, ": mClearForceValidated"); 478 mForceCellularValidated = false; 479 updateConnectivity(); 480 }; 481 isInGroupDataSwitch(int subId1, int subId2)482 boolean isInGroupDataSwitch(int subId1, int subId2) { 483 SubscriptionInfo info1 = mSubscriptionManager.getActiveSubscriptionInfo(subId1); 484 SubscriptionInfo info2 = mSubscriptionManager.getActiveSubscriptionInfo(subId2); 485 return (info1 != null && info2 != null && info1.getGroupUuid() != null 486 && info1.getGroupUuid().equals(info2.getGroupUuid())); 487 } 488 keepCellularValidationBitInSwitch(int sourceSubId, int destSubId)489 boolean keepCellularValidationBitInSwitch(int sourceSubId, int destSubId) { 490 return mValidatedTransports.get(TRANSPORT_CELLULAR) 491 && isInGroupDataSwitch(sourceSubId, destSubId); 492 } 493 getDataSaverController()494 public DataSaverController getDataSaverController() { 495 return mDataSaverController; 496 } 497 498 @VisibleForTesting registerListeners()499 void registerListeners() { 500 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 501 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 502 mobileSignalController.registerListener(); 503 } 504 if (mSubscriptionListener == null) { 505 mSubscriptionListener = new SubListener(mBgLooper); 506 } 507 mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener); 508 mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener); 509 510 // broadcasts 511 IntentFilter filter = new IntentFilter(); 512 filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 513 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 514 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 515 filter.addAction(Intent.ACTION_SERVICE_STATE); 516 filter.addAction(Intent.ACTION_SIM_STATE_CHANGED); 517 filter.addAction(Settings.Panel.ACTION_INTERNET_CONNECTIVITY); 518 filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); 519 filter.addAction(TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); 520 filter.addAction(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED); 521 filter.addAction(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED); 522 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 523 mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler); 524 mListening = true; 525 526 // Initial setup of connectivity. Handled as if we had received a sticky broadcast of 527 // ConnectivityManager.CONNECTIVITY_ACTION. 528 mReceiverHandler.post(this::updateConnectivity); 529 530 // Initial setup of WifiSignalController. Handled as if we had received a sticky broadcast 531 // of WifiManager.WIFI_STATE_CHANGED_ACTION or WifiManager.NETWORK_STATE_CHANGED_ACTION 532 mReceiverHandler.post(mWifiSignalController::fetchInitialState); 533 534 // Initial setup of mLastServiceState. Only run if there is no service state yet. 535 // Each MobileSignalController will also get their corresponding 536 mReceiverHandler.post(() -> { 537 if (mLastServiceState == null) { 538 mLastServiceState = mPhone.getServiceState(); 539 if (mMobileSignalControllers.size() == 0) { 540 recalculateEmergency(); 541 } 542 } 543 }); 544 updateMobileControllers(); 545 546 // Initial setup of emergency information. Handled as if we had received a sticky broadcast 547 // of TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED. 548 mReceiverHandler.post(this::recalculateEmergency); 549 } 550 unregisterListeners()551 private void unregisterListeners() { 552 mListening = false; 553 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 554 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 555 mobileSignalController.unregisterListener(); 556 } 557 mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener); 558 mBroadcastDispatcher.unregisterReceiver(this); 559 } 560 561 @Override getAccessPointController()562 public AccessPointController getAccessPointController() { 563 return mAccessPoints; 564 } 565 566 @Override getMobileDataController()567 public DataUsageController getMobileDataController() { 568 return mDataUsageController; 569 } 570 571 /** */ addEmergencyListener(EmergencyListener listener)572 public void addEmergencyListener(EmergencyListener listener) { 573 mCallbackHandler.setListening(listener, true); 574 mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly()); 575 } 576 577 /** */ removeEmergencyListener(EmergencyListener listener)578 public void removeEmergencyListener(EmergencyListener listener) { 579 mCallbackHandler.setListening(listener, false); 580 } 581 582 /** */ hasMobileDataFeature()583 public boolean hasMobileDataFeature() { 584 return mHasMobileDataFeature; 585 } 586 587 /** */ hasVoiceCallingFeature()588 public boolean hasVoiceCallingFeature() { 589 return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE; 590 } 591 getProcessedTransportTypes(NetworkCapabilities networkCapabilities)592 private int[] getProcessedTransportTypes(NetworkCapabilities networkCapabilities) { 593 int[] transportTypes = networkCapabilities.getTransportTypes(); 594 for (int i = 0; i < transportTypes.length; i++) { 595 // For VCN over WiFi, the transportType is set to be TRANSPORT_CELLULAR in the 596 // NetworkCapabilities, but we need to convert it into TRANSPORT_WIFI in order to 597 // distinguish it from VCN over Cellular. 598 if (transportTypes[i] == NetworkCapabilities.TRANSPORT_CELLULAR 599 && Utils.tryGetWifiInfoForVcn(networkCapabilities) != null) { 600 transportTypes[i] = NetworkCapabilities.TRANSPORT_WIFI; 601 break; 602 } 603 } 604 return transportTypes; 605 } 606 getDataController()607 private MobileSignalController getDataController() { 608 int dataSubId = mSubDefaults.getActiveDataSubId(); 609 return getControllerWithSubId(dataSubId); 610 } 611 getControllerWithSubId(int subId)612 private MobileSignalController getControllerWithSubId(int subId) { 613 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 614 if (DEBUG) Log.e(TAG, "No data sim selected"); 615 return mDefaultSignalController; 616 } 617 if (mMobileSignalControllers.indexOfKey(subId) >= 0) { 618 return mMobileSignalControllers.get(subId); 619 } 620 if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + subId); 621 return mDefaultSignalController; 622 } 623 624 @Override getMobileDataNetworkName()625 public String getMobileDataNetworkName() { 626 MobileSignalController controller = getDataController(); 627 return controller != null ? controller.getState().networkNameData : ""; 628 } 629 630 @Override isMobileDataNetworkInService()631 public boolean isMobileDataNetworkInService() { 632 MobileSignalController controller = getDataController(); 633 return controller != null && controller.isInService(); 634 } 635 636 @Override getNumberSubscriptions()637 public int getNumberSubscriptions() { 638 return mMobileSignalControllers.size(); 639 } 640 isDataControllerDisabled()641 boolean isDataControllerDisabled() { 642 MobileSignalController dataController = getDataController(); 643 if (dataController == null) { 644 return false; 645 } 646 647 return dataController.isDataDisabled(); 648 } 649 isCarrierMergedWifi(int subId)650 boolean isCarrierMergedWifi(int subId) { 651 return mWifiSignalController.isCarrierMergedWifi(subId); 652 } 653 isEthernetDefault()654 boolean isEthernetDefault() { 655 return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET); 656 } 657 getNetworkNameForCarrierWiFi(int subId)658 String getNetworkNameForCarrierWiFi(int subId) { 659 MobileSignalController controller = getControllerWithSubId(subId); 660 return controller != null ? controller.getNetworkNameForCarrierWiFi() : ""; 661 } 662 notifyControllersMobileDataChanged()663 private void notifyControllersMobileDataChanged() { 664 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 665 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 666 mobileSignalController.onMobileDataChanged(); 667 } 668 } 669 isEmergencyOnly()670 boolean isEmergencyOnly() { 671 if (mMobileSignalControllers.size() == 0) { 672 // When there are no active subscriptions, determine emengency state from last 673 // broadcast. 674 mEmergencySource = EMERGENCY_NO_CONTROLLERS; 675 return mLastServiceState != null && mLastServiceState.isEmergencyOnly(); 676 } 677 int voiceSubId = mSubDefaults.getDefaultVoiceSubId(); 678 if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) { 679 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 680 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 681 if (!mobileSignalController.getState().isEmergency) { 682 mEmergencySource = EMERGENCY_FIRST_CONTROLLER 683 + mobileSignalController.mSubscriptionInfo.getSubscriptionId(); 684 if (DEBUG) Log.d(TAG, "Found emergency " + mobileSignalController.mTag); 685 return false; 686 } 687 } 688 } 689 if (mMobileSignalControllers.indexOfKey(voiceSubId) >= 0) { 690 mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId; 691 if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId); 692 return mMobileSignalControllers.get(voiceSubId).getState().isEmergency; 693 } 694 // If we have the wrong subId but there is only one sim anyway, assume it should be the 695 // default. 696 if (mMobileSignalControllers.size() == 1) { 697 mEmergencySource = EMERGENCY_ASSUMED_VOICE_CONTROLLER 698 + mMobileSignalControllers.keyAt(0); 699 if (DEBUG) { 700 Log.d(TAG, "Getting assumed emergency from " 701 + mMobileSignalControllers.keyAt(0)); 702 } 703 return mMobileSignalControllers.valueAt(0).getState().isEmergency; 704 } 705 if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId); 706 mEmergencySource = EMERGENCY_NO_SUB + voiceSubId; 707 // Something is wrong, better assume we can't make calls... 708 return true; 709 } 710 711 /** 712 * Emergency status may have changed (triggered by MobileSignalController), 713 * so we should recheck and send out the state to listeners. 714 */ recalculateEmergency()715 void recalculateEmergency() { 716 mIsEmergency = isEmergencyOnly(); 717 mCallbackHandler.setEmergencyCallsOnly(mIsEmergency); 718 } 719 720 @Override addCallback(@onNull SignalCallback cb)721 public void addCallback(@NonNull SignalCallback cb) { 722 cb.setSubs(mCurrentSubscriptions); 723 cb.setIsAirplaneMode( 724 new IconState( 725 mAirplaneMode, 726 TelephonyIcons.FLIGHT_MODE_ICON, 727 mContext.getString(R.string.accessibility_airplane_mode))); 728 cb.setNoSims(mHasNoSubs, mSimDetected); 729 cb.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition, mNoNetworksAvailable); 730 mWifiSignalController.notifyListeners(cb); 731 mEthernetSignalController.notifyListeners(cb); 732 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 733 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 734 mobileSignalController.notifyListeners(cb); 735 } 736 mCallbackHandler.setListening(cb, true); 737 } 738 739 @Override removeCallback(@onNull SignalCallback cb)740 public void removeCallback(@NonNull SignalCallback cb) { 741 mCallbackHandler.setListening(cb, false); 742 } 743 744 @Override setWifiEnabled(final boolean enabled)745 public void setWifiEnabled(final boolean enabled) { 746 new AsyncTask<Void, Void, Void>() { 747 @Override 748 protected Void doInBackground(Void... args) { 749 mWifiManager.setWifiEnabled(enabled); 750 return null; 751 } 752 }.execute(); 753 } 754 onUserSwitched(int newUserId)755 private void onUserSwitched(int newUserId) { 756 mCurrentUserId = newUserId; 757 mAccessPoints.onUserSwitched(newUserId); 758 updateConnectivity(); 759 } 760 761 @Override onReceive(Context context, Intent intent)762 public void onReceive(Context context, Intent intent) { 763 if (CHATTY) { 764 Log.d(TAG, "onReceive: intent=" + intent); 765 } 766 final String action = intent.getAction(); 767 mLogBuffer.log( 768 TAG, 769 LogLevel.INFO, 770 logMessage -> { 771 logMessage.setStr1(action); 772 return Unit.INSTANCE; 773 }, 774 logMessage -> String.format( 775 Locale.US, 776 "Received broadcast with action \"%s\"", 777 logMessage.getStr1())); 778 switch (action) { 779 case ConnectivityManager.CONNECTIVITY_ACTION: 780 updateConnectivity(); 781 break; 782 case Intent.ACTION_AIRPLANE_MODE_CHANGED: 783 refreshLocale(); 784 updateAirplaneMode(false); 785 break; 786 case TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED: 787 // We are using different subs now, we might be able to make calls. 788 recalculateEmergency(); 789 break; 790 case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: 791 // Notify every MobileSignalController so they can know whether they are the 792 // data sim or not. 793 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 794 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 795 controller.handleBroadcast(intent); 796 } 797 mConfig = Config.readConfig(mContext); 798 mReceiverHandler.post(this::handleConfigurationChanged); 799 break; 800 801 case TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED: { 802 // Notify the relevant MobileSignalController of the change 803 int subId = intent.getIntExtra( 804 TelephonyManager.EXTRA_SUBSCRIPTION_ID, 805 INVALID_SUBSCRIPTION_ID 806 ); 807 if (SubscriptionManager.isValidSubscriptionId(subId)) { 808 if (mMobileSignalControllers.indexOfKey(subId) >= 0) { 809 mMobileSignalControllers.get(subId).handleBroadcast(intent); 810 } 811 } 812 } 813 break; 814 case Intent.ACTION_SIM_STATE_CHANGED: 815 // Avoid rebroadcast because SysUI is direct boot aware. 816 if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) { 817 break; 818 } 819 // Might have different subscriptions now. 820 updateMobileControllers(); 821 break; 822 case Intent.ACTION_SERVICE_STATE: 823 mLastServiceState = ServiceState.newFromBundle(intent.getExtras()); 824 if (mMobileSignalControllers.size() == 0) { 825 // If none of the subscriptions are active, we might need to recalculate 826 // emergency state. 827 recalculateEmergency(); 828 } 829 break; 830 case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: 831 mConfig = Config.readConfig(mContext); 832 mReceiverHandler.post(this::handleConfigurationChanged); 833 break; 834 case Settings.Panel.ACTION_INTERNET_CONNECTIVITY: 835 mMainHandler.post(() -> mInternetDialogManager.create(true, 836 mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi(), 837 null /* view */)); 838 break; 839 default: 840 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, 841 INVALID_SUBSCRIPTION_ID); 842 if (SubscriptionManager.isValidSubscriptionId(subId)) { 843 if (mMobileSignalControllers.indexOfKey(subId) >= 0) { 844 mMobileSignalControllers.get(subId).handleBroadcast(intent); 845 } else { 846 // Can't find this subscription... We must be out of date. 847 updateMobileControllers(); 848 } 849 } else { 850 // No sub id, must be for the wifi. 851 mWifiSignalController.handleBroadcast(intent); 852 } 853 break; 854 } 855 } 856 857 @VisibleForTesting handleConfigurationChanged()858 void handleConfigurationChanged() { 859 updateMobileControllers(); 860 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 861 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 862 controller.setConfiguration(mConfig); 863 } 864 refreshLocale(); 865 } 866 updateMobileControllers()867 private void updateMobileControllers() { 868 if (!mListening) { 869 return; 870 } 871 doUpdateMobileControllers(); 872 } 873 filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions)874 private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) { 875 if (subscriptions.size() == 2) { 876 SubscriptionInfo info1 = subscriptions.get(0); 877 SubscriptionInfo info2 = subscriptions.get(1); 878 if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) { 879 // If both subscriptions are primary, show both. 880 if (!info1.isOpportunistic() && !info2.isOpportunistic()) return; 881 882 // If carrier required, always show signal bar of primary subscription. 883 // Otherwise, show whichever subscription is currently active for Internet. 884 boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig() 885 .getBoolean(CarrierConfigManager 886 .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN); 887 if (alwaysShowPrimary) { 888 subscriptions.remove(info1.isOpportunistic() ? info1 : info2); 889 } else { 890 subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription 891 ? info2 : info1); 892 } 893 } 894 } 895 } 896 897 @VisibleForTesting doUpdateMobileControllers()898 void doUpdateMobileControllers() { 899 List<SubscriptionInfo> subscriptions = mSubscriptionManager 900 .getCompleteActiveSubscriptionInfoList(); 901 if (subscriptions == null) { 902 subscriptions = Collections.emptyList(); 903 } 904 905 filterMobileSubscriptionInSameGroup(subscriptions); 906 907 // If there have been no relevant changes to any of the subscriptions, we can leave as is. 908 if (hasCorrectMobileControllers(subscriptions)) { 909 // Even if the controllers are correct, make sure we have the right no sims state. 910 // Such as on boot, don't need any controllers, because there are no sims, 911 // but we still need to update the no sim state. 912 updateNoSims(); 913 return; 914 } 915 synchronized (mLock) { 916 setCurrentSubscriptionsLocked(subscriptions); 917 } 918 updateNoSims(); 919 recalculateEmergency(); 920 } 921 922 @VisibleForTesting updateNoSims()923 protected void updateNoSims() { 924 boolean hasNoSubs = mHasMobileDataFeature && mMobileSignalControllers.size() == 0; 925 boolean simDetected = hasAnySim(); 926 if (hasNoSubs != mHasNoSubs || simDetected != mSimDetected) { 927 mHasNoSubs = hasNoSubs; 928 mSimDetected = simDetected; 929 mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected); 930 } 931 } 932 hasAnySim()933 private boolean hasAnySim() { 934 int simCount = mPhone.getActiveModemCount(); 935 for (int i = 0; i < simCount; i++) { 936 int state = mPhone.getSimState(i); 937 if (state != TelephonyManager.SIM_STATE_ABSENT 938 && state != TelephonyManager.SIM_STATE_UNKNOWN) { 939 return true; 940 } 941 } 942 return false; 943 } 944 945 @GuardedBy("mLock") 946 @VisibleForTesting setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions)947 void setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions) { 948 Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() { 949 @Override 950 public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) { 951 return lhs.getSimSlotIndex() == rhs.getSimSlotIndex() 952 ? lhs.getSubscriptionId() - rhs.getSubscriptionId() 953 : lhs.getSimSlotIndex() - rhs.getSimSlotIndex(); 954 } 955 }); 956 Log.i( 957 TAG, 958 String.format( 959 Locale.US, 960 "Subscriptions changed: %s", 961 createSubscriptionChangeStatement(mCurrentSubscriptions, subscriptions))); 962 mCurrentSubscriptions = subscriptions; 963 964 SparseArray<MobileSignalController> cachedControllers = 965 new SparseArray<MobileSignalController>(); 966 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 967 cachedControllers.put(mMobileSignalControllers.keyAt(i), 968 mMobileSignalControllers.valueAt(i)); 969 } 970 mMobileSignalControllers.clear(); 971 final int num = subscriptions.size(); 972 for (int i = 0; i < num; i++) { 973 int subId = subscriptions.get(i).getSubscriptionId(); 974 // If we have a copy of this controller already reuse it, otherwise make a new one. 975 if (cachedControllers.indexOfKey(subId) >= 0) { 976 mMobileSignalControllers.put(subId, cachedControllers.get(subId)); 977 cachedControllers.remove(subId); 978 } else { 979 MobileSignalController controller = mMobileFactory.createMobileSignalController( 980 mConfig, 981 mHasMobileDataFeature, 982 mPhone.createForSubscriptionId(subId), 983 this, 984 subscriptions.get(i), 985 mSubDefaults, 986 mReceiverHandler.getLooper() 987 ); 988 controller.setUserSetupComplete(mUserSetup); 989 mMobileSignalControllers.put(subId, controller); 990 if (subscriptions.get(i).getSimSlotIndex() == 0) { 991 mDefaultSignalController = controller; 992 } 993 if (mListening) { 994 controller.registerListener(); 995 } 996 } 997 } 998 if (mListening) { 999 for (int i = 0; i < cachedControllers.size(); i++) { 1000 int key = cachedControllers.keyAt(i); 1001 if (cachedControllers.get(key) == mDefaultSignalController) { 1002 mDefaultSignalController = null; 1003 } 1004 cachedControllers.get(key).unregisterListener(); 1005 } 1006 } 1007 mCallbackHandler.setSubs(subscriptions); 1008 notifyAllListeners(); 1009 1010 // There may be new MobileSignalControllers around, make sure they get the current 1011 // inet condition and airplane mode. 1012 pushConnectivityToSignals(); 1013 updateAirplaneMode(true /* force */); 1014 } 1015 setUserSetupComplete(final boolean userSetup)1016 private void setUserSetupComplete(final boolean userSetup) { 1017 mReceiverHandler.post(() -> handleSetUserSetupComplete(userSetup)); 1018 } 1019 handleSetUserSetupComplete(boolean userSetup)1020 private void handleSetUserSetupComplete(boolean userSetup) { 1021 mUserSetup = userSetup; 1022 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1023 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 1024 controller.setUserSetupComplete(mUserSetup); 1025 } 1026 } 1027 1028 @VisibleForTesting isUserSetup()1029 boolean isUserSetup() { 1030 return mUserSetup; 1031 } 1032 1033 @VisibleForTesting hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions)1034 boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) { 1035 if (allSubscriptions.size() != mMobileSignalControllers.size()) { 1036 return false; 1037 } 1038 for (SubscriptionInfo info : allSubscriptions) { 1039 if (mMobileSignalControllers.indexOfKey(info.getSubscriptionId()) < 0) { 1040 return false; 1041 } 1042 } 1043 return true; 1044 } 1045 1046 @VisibleForTesting setNoNetworksAvailable(boolean noNetworksAvailable)1047 void setNoNetworksAvailable(boolean noNetworksAvailable) { 1048 mNoNetworksAvailable = noNetworksAvailable; 1049 } 1050 updateAirplaneMode(boolean force)1051 private void updateAirplaneMode(boolean force) { 1052 boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(), 1053 Settings.Global.AIRPLANE_MODE_ON, 0) == 1); 1054 if (airplaneMode != mAirplaneMode || force) { 1055 mAirplaneMode = airplaneMode; 1056 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1057 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 1058 mobileSignalController.setAirplaneMode(mAirplaneMode); 1059 } 1060 notifyListeners(); 1061 } 1062 } 1063 refreshLocale()1064 private void refreshLocale() { 1065 Locale current = mContext.getResources().getConfiguration().locale; 1066 if (!current.equals(mLocale)) { 1067 mLocale = current; 1068 mWifiSignalController.refreshLocale(); 1069 notifyAllListeners(); 1070 } 1071 } 1072 1073 /** 1074 * Forces update of all callbacks on both SignalClusters and 1075 * NetworkSignalChangedCallbacks. 1076 */ notifyAllListeners()1077 private void notifyAllListeners() { 1078 notifyListeners(); 1079 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1080 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 1081 mobileSignalController.notifyListeners(); 1082 } 1083 mWifiSignalController.notifyListeners(); 1084 mEthernetSignalController.notifyListeners(); 1085 } 1086 1087 /** 1088 * Notifies listeners of changes in state of to the NetworkController, but 1089 * does not notify for any info on SignalControllers, for that call 1090 * notifyAllListeners. 1091 */ notifyListeners()1092 private void notifyListeners() { 1093 mCallbackHandler.setIsAirplaneMode( 1094 new IconState( 1095 mAirplaneMode, 1096 TelephonyIcons.FLIGHT_MODE_ICON, 1097 mContext.getString(R.string.accessibility_airplane_mode))); 1098 mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected); 1099 } 1100 1101 /** 1102 * Update the Inet conditions and what network we are connected to. 1103 */ updateConnectivity()1104 private void updateConnectivity() { 1105 mConnectedTransports.clear(); 1106 mValidatedTransports.clear(); 1107 if (mLastDefaultNetworkCapabilities != null) { 1108 for (int transportType : mLastDefaultNetworkCapabilities.getTransportTypes()) { 1109 if (transportType != NetworkCapabilities.TRANSPORT_CELLULAR 1110 && transportType != NetworkCapabilities.TRANSPORT_WIFI 1111 && transportType != NetworkCapabilities.TRANSPORT_ETHERNET) { 1112 continue; 1113 } 1114 if (transportType == NetworkCapabilities.TRANSPORT_CELLULAR 1115 && Utils.tryGetWifiInfoForVcn(mLastDefaultNetworkCapabilities) != null) { 1116 mConnectedTransports.set(NetworkCapabilities.TRANSPORT_WIFI); 1117 if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) { 1118 mValidatedTransports.set(NetworkCapabilities.TRANSPORT_WIFI); 1119 } 1120 } else { 1121 mConnectedTransports.set(transportType); 1122 if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) { 1123 mValidatedTransports.set(transportType); 1124 } 1125 } 1126 } 1127 } 1128 1129 if (mForceCellularValidated) mValidatedTransports.set(TRANSPORT_CELLULAR); 1130 1131 if (CHATTY) { 1132 Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports); 1133 Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports); 1134 } 1135 1136 mInetCondition = mValidatedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR) 1137 || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_WIFI) 1138 || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET); 1139 1140 pushConnectivityToSignals(); 1141 mNoDefaultNetwork = !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR) 1142 && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_WIFI) 1143 && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET); 1144 mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition, 1145 mNoNetworksAvailable); 1146 } 1147 1148 /** 1149 * Pushes the current connectivity state to all SignalControllers. 1150 */ pushConnectivityToSignals()1151 private void pushConnectivityToSignals() { 1152 // We want to update all the icons, all at once, for any condition change 1153 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1154 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 1155 mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 1156 } 1157 mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 1158 mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 1159 } 1160 1161 /** */ 1162 @NeverCompile dump(PrintWriter pw, String[] args)1163 public void dump(PrintWriter pw, String[] args) { 1164 pw.println("NetworkController state:"); 1165 pw.println(" mUserSetup=" + mUserSetup); 1166 1167 pw.println(" - telephony ------"); 1168 pw.print(" hasVoiceCallingFeature()="); 1169 pw.println(hasVoiceCallingFeature()); 1170 pw.println(" mListening=" + mListening); 1171 pw.println(" mActiveMobileDataSubscription=" + mActiveMobileDataSubscription); 1172 1173 pw.println(" - connectivity ------"); 1174 pw.print(" mConnectedTransports="); 1175 pw.println(mConnectedTransports); 1176 pw.print(" mValidatedTransports="); 1177 pw.println(mValidatedTransports); 1178 pw.print(" mInetCondition="); 1179 pw.println(mInetCondition); 1180 pw.print(" mAirplaneMode="); 1181 pw.println(mAirplaneMode); 1182 pw.print(" mLocale="); 1183 pw.println(mLocale); 1184 pw.print(" mLastServiceState="); 1185 pw.println(mLastServiceState); 1186 pw.print(" mIsEmergency="); 1187 pw.println(mIsEmergency); 1188 pw.print(" mEmergencySource="); 1189 pw.println(emergencyToString(mEmergencySource)); 1190 1191 pw.println(" - DefaultNetworkCallback -----"); 1192 int size = 0; 1193 for (int i = 0; i < HISTORY_SIZE; i++) { 1194 if (mHistory[i] != null) { 1195 size++; 1196 } 1197 } 1198 for (int i = mHistoryIndex + HISTORY_SIZE - 1; 1199 i >= mHistoryIndex + HISTORY_SIZE - size; i--) { 1200 pw.println(" Previous NetworkCallback(" + (mHistoryIndex + HISTORY_SIZE - i) + "): " 1201 + mHistory[i & (HISTORY_SIZE - 1)]); 1202 } 1203 1204 pw.println(" - config ------"); 1205 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1206 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 1207 mobileSignalController.dump(pw); 1208 } 1209 mWifiSignalController.dump(pw); 1210 1211 mEthernetSignalController.dump(pw); 1212 1213 mAccessPoints.dump(pw); 1214 1215 mCallbackHandler.dump(pw); 1216 } 1217 emergencyToString(int emergencySource)1218 private static String emergencyToString(int emergencySource) { 1219 if (emergencySource > EMERGENCY_NO_SUB) { 1220 return "ASSUMED_VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) 1221 + ")"; 1222 } else if (emergencySource > EMERGENCY_NO_SUB) { 1223 return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")"; 1224 } else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) { 1225 return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")"; 1226 } else if (emergencySource > EMERGENCY_FIRST_CONTROLLER) { 1227 return "FIRST_CONTROLLER(" + (emergencySource - EMERGENCY_FIRST_CONTROLLER) + ")"; 1228 } else if (emergencySource == EMERGENCY_NO_CONTROLLERS) { 1229 return "NO_CONTROLLERS"; 1230 } 1231 return "UNKNOWN_SOURCE"; 1232 } 1233 1234 private boolean mDemoInetCondition; 1235 1236 @Override onDemoModeStarted()1237 public void onDemoModeStarted() { 1238 if (DEBUG) Log.d(TAG, "Entering demo mode"); 1239 unregisterListeners(); 1240 mDemoInetCondition = mInetCondition; 1241 } 1242 1243 @Override onDemoModeFinished()1244 public void onDemoModeFinished() { 1245 if (DEBUG) Log.d(TAG, "Exiting demo mode"); 1246 // Update what MobileSignalControllers, because they may change 1247 // to set the number of sim slots. 1248 updateMobileControllers(); 1249 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1250 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 1251 controller.resetLastState(); 1252 } 1253 mWifiSignalController.resetLastState(); 1254 mReceiverHandler.post(mRegisterListeners); 1255 notifyAllListeners(); 1256 } 1257 1258 @Override dispatchDemoCommand(String command, Bundle args)1259 public void dispatchDemoCommand(String command, Bundle args) { 1260 if (!mDemoModeController.isInDemoMode()) { 1261 return; 1262 } 1263 1264 String airplane = args.getString("airplane"); 1265 if (airplane != null) { 1266 boolean show = airplane.equals("show"); 1267 mCallbackHandler.setIsAirplaneMode( 1268 new IconState( 1269 show, 1270 TelephonyIcons.FLIGHT_MODE_ICON, 1271 mContext.getString(R.string.accessibility_airplane_mode))); 1272 } 1273 String fully = args.getString("fully"); 1274 if (fully != null) { 1275 mDemoInetCondition = Boolean.parseBoolean(fully); 1276 BitSet connected = new BitSet(); 1277 1278 if (mDemoInetCondition) { 1279 connected.set(mWifiSignalController.mTransportType); 1280 } 1281 mWifiSignalController.updateConnectivity(connected, connected); 1282 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1283 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 1284 if (mDemoInetCondition) { 1285 connected.set(controller.mTransportType); 1286 } 1287 controller.updateConnectivity(connected, connected); 1288 } 1289 } 1290 String sims = args.getString("sims"); 1291 if (sims != null) { 1292 int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8); 1293 List<SubscriptionInfo> subs = new ArrayList<>(); 1294 if (num != mMobileSignalControllers.size()) { 1295 mMobileSignalControllers.clear(); 1296 int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); 1297 for (int i = start /* get out of normal index range */; i < start + num; i++) { 1298 subs.add(addDemoModeSignalController(i, i)); 1299 } 1300 mCallbackHandler.setSubs(subs); 1301 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1302 int key = mMobileSignalControllers.keyAt(i); 1303 MobileSignalController controller = mMobileSignalControllers.get(key); 1304 controller.notifyListeners(); 1305 } 1306 } 1307 } 1308 String nosim = args.getString("nosim"); 1309 if (nosim != null) { 1310 mHasNoSubs = nosim.equals("show"); 1311 mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected); 1312 } 1313 String mobile = args.getString("mobile"); 1314 if (mobile != null) { 1315 boolean show = mobile.equals("show"); 1316 String datatype = args.getString("datatype"); 1317 String slotString = args.getString("slot"); 1318 int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString); 1319 slot = MathUtils.constrain(slot, 0, 8); 1320 String carrierIdString = args.getString("carrierid"); 1321 int carrierId = TextUtils.isEmpty(carrierIdString) ? 0 1322 : Integer.parseInt(carrierIdString); 1323 // Ensure we have enough sim slots 1324 // TODO(b/336357360): This is the origination of the infinite loop bug, for those 1325 // following along at home. 1326 List<SubscriptionInfo> subs = new ArrayList<>(); 1327 while (mMobileSignalControllers.size() <= slot) { 1328 int nextSlot = mMobileSignalControllers.size(); 1329 subs.add(addDemoModeSignalController(nextSlot, nextSlot)); 1330 } 1331 if (!subs.isEmpty()) { 1332 mCallbackHandler.setSubs(subs); 1333 } 1334 // Hack to index linearly for easy use. 1335 MobileSignalController controller = mMobileSignalControllers.valueAt(slot); 1336 if (carrierId != 0) { 1337 controller.getState().setCarrierId(carrierId); 1338 } 1339 controller.getState().dataSim = datatype != null; 1340 controller.getState().isDefault = datatype != null; 1341 controller.getState().dataConnected = datatype != null; 1342 if (datatype != null) { 1343 controller.getState().iconGroup = 1344 datatype.equals("1x") ? TelephonyIcons.ONE_X : 1345 datatype.equals("3g") ? TelephonyIcons.THREE_G : 1346 datatype.equals("4g") ? TelephonyIcons.FOUR_G : 1347 datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS : 1348 datatype.equals("5g") ? TelephonyIcons.NR_5G : 1349 datatype.equals("5ge") ? TelephonyIcons.LTE_CA_5G_E : 1350 datatype.equals("5g+") ? TelephonyIcons.NR_5G_PLUS : 1351 datatype.equals("e") ? TelephonyIcons.E : 1352 datatype.equals("g") ? TelephonyIcons.G : 1353 datatype.equals("h") ? TelephonyIcons.H : 1354 datatype.equals("h+") ? TelephonyIcons.H_PLUS : 1355 datatype.equals("lte") ? TelephonyIcons.LTE : 1356 datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS : 1357 datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED : 1358 datatype.equals("not") ? TelephonyIcons.NOT_DEFAULT_DATA : 1359 TelephonyIcons.UNKNOWN; 1360 } 1361 if (args.containsKey("roam")) { 1362 controller.getState().roaming = "show".equals(args.getString("roam")); 1363 } 1364 String level = args.getString("level"); 1365 if (level != null) { 1366 controller.getState().level = level.equals("null") ? -1 1367 : Math.min(Integer.parseInt(level), 1368 CellSignalStrength.getNumSignalStrengthLevels()); 1369 controller.getState().connected = controller.getState().level >= 0; 1370 } 1371 if (args.containsKey("inflate")) { 1372 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1373 mMobileSignalControllers.valueAt(i).mInflateSignalStrengths = 1374 "true".equals(args.getString("inflate")); 1375 } 1376 } 1377 String activity = args.getString("activity"); 1378 if (activity != null) { 1379 controller.getState().dataConnected = true; 1380 switch (activity) { 1381 case "inout": 1382 controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT); 1383 break; 1384 case "in": 1385 controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN); 1386 break; 1387 case "out": 1388 controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT); 1389 break; 1390 default: 1391 controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE); 1392 break; 1393 } 1394 } else { 1395 controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE); 1396 } 1397 controller.getState().enabled = show; 1398 controller.notifyListeners(); 1399 } 1400 String carrierNetworkChange = args.getString("carriernetworkchange"); 1401 if (carrierNetworkChange != null) { 1402 boolean show = carrierNetworkChange.equals("show"); 1403 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1404 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 1405 controller.setCarrierNetworkChangeMode(show); 1406 } 1407 } 1408 } 1409 1410 @Override demoCommands()1411 public List<String> demoCommands() { 1412 List<String> s = new ArrayList<>(); 1413 s.add(DemoMode.COMMAND_NETWORK); 1414 return s; 1415 } 1416 recordLastNetworkCallback(String callback)1417 private void recordLastNetworkCallback(String callback) { 1418 mHistory[mHistoryIndex] = callback; 1419 mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE; 1420 } 1421 addDemoModeSignalController(int id, int simSlotIndex)1422 private SubscriptionInfo addDemoModeSignalController(int id, int simSlotIndex) { 1423 SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0, 1424 null, null, null, "", false, null, null); 1425 1426 MobileSignalController controller = mMobileFactory.createMobileSignalController( 1427 mConfig, 1428 mHasMobileDataFeature, 1429 mPhone.createForSubscriptionId(info.getSubscriptionId()), 1430 this, 1431 info, 1432 mSubDefaults, 1433 mReceiverHandler.getLooper() 1434 ); 1435 1436 mMobileSignalControllers.put(id, controller); 1437 controller.getState().userSetup = true; 1438 return info; 1439 } 1440 1441 /** */ isRadioOn()1442 public boolean isRadioOn() { 1443 return !mAirplaneMode; 1444 } 1445 1446 private class SubListener extends OnSubscriptionsChangedListener { SubListener(Looper looper)1447 SubListener(Looper looper) { 1448 super(looper); 1449 } 1450 1451 @Override onSubscriptionsChanged()1452 public void onSubscriptionsChanged() { 1453 updateMobileControllers(); 1454 } 1455 } 1456 1457 /** 1458 * Used to register listeners from the BG Looper, this way the PhoneStateListeners that 1459 * get created will also run on the BG Looper. 1460 */ 1461 private final Runnable mRegisterListeners = () -> registerListeners(); 1462 1463 /** Returns a logging statement for the given old and new list of {@link SubscriptionInfo} */ createSubscriptionChangeStatement( final @Nullable List<SubscriptionInfo> oldSubscriptions, final @Nullable List<SubscriptionInfo> newSubscriptions)1464 private static String createSubscriptionChangeStatement( 1465 final @Nullable List<SubscriptionInfo> oldSubscriptions, 1466 final @Nullable List<SubscriptionInfo> newSubscriptions) { 1467 return String.format( 1468 Locale.US, 1469 "old=%s, new=%s", 1470 toSubscriptionIds(oldSubscriptions), 1471 toSubscriptionIds(newSubscriptions)); 1472 } 1473 1474 /** Returns to a list of subscription IDs for the given list of {@link SubscriptionInfo} */ 1475 @Nullable toSubscriptionIds( final @Nullable List<SubscriptionInfo> subscriptions)1476 private static List<Integer> toSubscriptionIds( 1477 final @Nullable List<SubscriptionInfo> subscriptions) { 1478 return subscriptions != null ? subscriptions.stream().map( 1479 SubscriptionInfo::getSubscriptionId).collect(Collectors.toList()) : null; 1480 } 1481 } 1482