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(mConnectivityManager, networkCapabilities) 600 != null) { 601 transportTypes[i] = NetworkCapabilities.TRANSPORT_WIFI; 602 break; 603 } 604 } 605 return transportTypes; 606 } 607 getDataController()608 private MobileSignalController getDataController() { 609 int dataSubId = mSubDefaults.getActiveDataSubId(); 610 return getControllerWithSubId(dataSubId); 611 } 612 getControllerWithSubId(int subId)613 private MobileSignalController getControllerWithSubId(int subId) { 614 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 615 if (DEBUG) Log.e(TAG, "No data sim selected"); 616 return mDefaultSignalController; 617 } 618 if (mMobileSignalControllers.indexOfKey(subId) >= 0) { 619 return mMobileSignalControllers.get(subId); 620 } 621 if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + subId); 622 return mDefaultSignalController; 623 } 624 625 @Override getMobileDataNetworkName()626 public String getMobileDataNetworkName() { 627 MobileSignalController controller = getDataController(); 628 return controller != null ? controller.getState().networkNameData : ""; 629 } 630 631 @Override isMobileDataNetworkInService()632 public boolean isMobileDataNetworkInService() { 633 MobileSignalController controller = getDataController(); 634 return controller != null && controller.isInService(); 635 } 636 637 @Override getNumberSubscriptions()638 public int getNumberSubscriptions() { 639 return mMobileSignalControllers.size(); 640 } 641 isDataControllerDisabled()642 boolean isDataControllerDisabled() { 643 MobileSignalController dataController = getDataController(); 644 if (dataController == null) { 645 return false; 646 } 647 648 return dataController.isDataDisabled(); 649 } 650 isCarrierMergedWifi(int subId)651 boolean isCarrierMergedWifi(int subId) { 652 return mWifiSignalController.isCarrierMergedWifi(subId); 653 } 654 isEthernetDefault()655 boolean isEthernetDefault() { 656 return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET); 657 } 658 getNetworkNameForCarrierWiFi(int subId)659 String getNetworkNameForCarrierWiFi(int subId) { 660 MobileSignalController controller = getControllerWithSubId(subId); 661 return controller != null ? controller.getNetworkNameForCarrierWiFi() : ""; 662 } 663 notifyControllersMobileDataChanged()664 private void notifyControllersMobileDataChanged() { 665 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 666 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 667 mobileSignalController.onMobileDataChanged(); 668 } 669 } 670 isEmergencyOnly()671 boolean isEmergencyOnly() { 672 if (mMobileSignalControllers.size() == 0) { 673 // When there are no active subscriptions, determine emengency state from last 674 // broadcast. 675 mEmergencySource = EMERGENCY_NO_CONTROLLERS; 676 return mLastServiceState != null && mLastServiceState.isEmergencyOnly(); 677 } 678 int voiceSubId = mSubDefaults.getDefaultVoiceSubId(); 679 if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) { 680 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 681 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 682 if (!mobileSignalController.getState().isEmergency) { 683 mEmergencySource = EMERGENCY_FIRST_CONTROLLER 684 + mobileSignalController.mSubscriptionInfo.getSubscriptionId(); 685 if (DEBUG) Log.d(TAG, "Found emergency " + mobileSignalController.mTag); 686 return false; 687 } 688 } 689 } 690 if (mMobileSignalControllers.indexOfKey(voiceSubId) >= 0) { 691 mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId; 692 if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId); 693 return mMobileSignalControllers.get(voiceSubId).getState().isEmergency; 694 } 695 // If we have the wrong subId but there is only one sim anyway, assume it should be the 696 // default. 697 if (mMobileSignalControllers.size() == 1) { 698 mEmergencySource = EMERGENCY_ASSUMED_VOICE_CONTROLLER 699 + mMobileSignalControllers.keyAt(0); 700 if (DEBUG) { 701 Log.d(TAG, "Getting assumed emergency from " 702 + mMobileSignalControllers.keyAt(0)); 703 } 704 return mMobileSignalControllers.valueAt(0).getState().isEmergency; 705 } 706 if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId); 707 mEmergencySource = EMERGENCY_NO_SUB + voiceSubId; 708 // Something is wrong, better assume we can't make calls... 709 return true; 710 } 711 712 /** 713 * Emergency status may have changed (triggered by MobileSignalController), 714 * so we should recheck and send out the state to listeners. 715 */ recalculateEmergency()716 void recalculateEmergency() { 717 mIsEmergency = isEmergencyOnly(); 718 mCallbackHandler.setEmergencyCallsOnly(mIsEmergency); 719 } 720 721 @Override addCallback(@onNull SignalCallback cb)722 public void addCallback(@NonNull SignalCallback cb) { 723 cb.setSubs(mCurrentSubscriptions); 724 cb.setIsAirplaneMode( 725 new IconState( 726 mAirplaneMode, 727 TelephonyIcons.FLIGHT_MODE_ICON, 728 mContext.getString(R.string.accessibility_airplane_mode))); 729 cb.setNoSims(mHasNoSubs, mSimDetected); 730 cb.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition, mNoNetworksAvailable); 731 mWifiSignalController.notifyListeners(cb); 732 mEthernetSignalController.notifyListeners(cb); 733 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 734 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 735 mobileSignalController.notifyListeners(cb); 736 } 737 mCallbackHandler.setListening(cb, true); 738 } 739 740 @Override removeCallback(@onNull SignalCallback cb)741 public void removeCallback(@NonNull SignalCallback cb) { 742 mCallbackHandler.setListening(cb, false); 743 } 744 745 @Override setWifiEnabled(final boolean enabled)746 public void setWifiEnabled(final boolean enabled) { 747 new AsyncTask<Void, Void, Void>() { 748 @Override 749 protected Void doInBackground(Void... args) { 750 mWifiManager.setWifiEnabled(enabled); 751 return null; 752 } 753 }.execute(); 754 } 755 onUserSwitched(int newUserId)756 private void onUserSwitched(int newUserId) { 757 mCurrentUserId = newUserId; 758 mAccessPoints.onUserSwitched(newUserId); 759 updateConnectivity(); 760 } 761 762 @Override onReceive(Context context, Intent intent)763 public void onReceive(Context context, Intent intent) { 764 if (CHATTY) { 765 Log.d(TAG, "onReceive: intent=" + intent); 766 } 767 final String action = intent.getAction(); 768 mLogBuffer.log( 769 TAG, 770 LogLevel.INFO, 771 logMessage -> { 772 logMessage.setStr1(action); 773 return Unit.INSTANCE; 774 }, 775 logMessage -> String.format( 776 Locale.US, 777 "Received broadcast with action \"%s\"", 778 logMessage.getStr1())); 779 switch (action) { 780 case ConnectivityManager.CONNECTIVITY_ACTION: 781 updateConnectivity(); 782 break; 783 case Intent.ACTION_AIRPLANE_MODE_CHANGED: 784 refreshLocale(); 785 updateAirplaneMode(false); 786 break; 787 case TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED: 788 // We are using different subs now, we might be able to make calls. 789 recalculateEmergency(); 790 break; 791 case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: 792 // Notify every MobileSignalController so they can know whether they are the 793 // data sim or not. 794 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 795 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 796 controller.handleBroadcast(intent); 797 } 798 mConfig = Config.readConfig(mContext); 799 mReceiverHandler.post(this::handleConfigurationChanged); 800 break; 801 802 case TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED: { 803 // Notify the relevant MobileSignalController of the change 804 int subId = intent.getIntExtra( 805 TelephonyManager.EXTRA_SUBSCRIPTION_ID, 806 INVALID_SUBSCRIPTION_ID 807 ); 808 if (SubscriptionManager.isValidSubscriptionId(subId)) { 809 if (mMobileSignalControllers.indexOfKey(subId) >= 0) { 810 mMobileSignalControllers.get(subId).handleBroadcast(intent); 811 } 812 } 813 } 814 break; 815 case Intent.ACTION_SIM_STATE_CHANGED: 816 // Avoid rebroadcast because SysUI is direct boot aware. 817 if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) { 818 break; 819 } 820 // Might have different subscriptions now. 821 updateMobileControllers(); 822 break; 823 case Intent.ACTION_SERVICE_STATE: 824 mLastServiceState = ServiceState.newFromBundle(intent.getExtras()); 825 if (mMobileSignalControllers.size() == 0) { 826 // If none of the subscriptions are active, we might need to recalculate 827 // emergency state. 828 recalculateEmergency(); 829 } 830 break; 831 case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: 832 mConfig = Config.readConfig(mContext); 833 mReceiverHandler.post(this::handleConfigurationChanged); 834 break; 835 case Settings.Panel.ACTION_INTERNET_CONNECTIVITY: 836 mMainHandler.post(() -> mInternetDialogManager.create(true, 837 mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi(), 838 null /* view */)); 839 break; 840 default: 841 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, 842 INVALID_SUBSCRIPTION_ID); 843 if (SubscriptionManager.isValidSubscriptionId(subId)) { 844 if (mMobileSignalControllers.indexOfKey(subId) >= 0) { 845 mMobileSignalControllers.get(subId).handleBroadcast(intent); 846 } else { 847 // Can't find this subscription... We must be out of date. 848 updateMobileControllers(); 849 } 850 } else { 851 // No sub id, must be for the wifi. 852 mWifiSignalController.handleBroadcast(intent); 853 } 854 break; 855 } 856 } 857 858 @VisibleForTesting handleConfigurationChanged()859 void handleConfigurationChanged() { 860 updateMobileControllers(); 861 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 862 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 863 controller.setConfiguration(mConfig); 864 } 865 refreshLocale(); 866 } 867 updateMobileControllers()868 private void updateMobileControllers() { 869 if (!mListening) { 870 return; 871 } 872 doUpdateMobileControllers(); 873 } 874 filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions)875 private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) { 876 if (subscriptions.size() == 2) { 877 SubscriptionInfo info1 = subscriptions.get(0); 878 SubscriptionInfo info2 = subscriptions.get(1); 879 if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) { 880 // If both subscriptions are primary, show both. 881 if (!info1.isOpportunistic() && !info2.isOpportunistic()) return; 882 883 // If carrier required, always show signal bar of primary subscription. 884 // Otherwise, show whichever subscription is currently active for Internet. 885 boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig() 886 .getBoolean(CarrierConfigManager 887 .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN); 888 if (alwaysShowPrimary) { 889 subscriptions.remove(info1.isOpportunistic() ? info1 : info2); 890 } else { 891 subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription 892 ? info2 : info1); 893 } 894 } 895 } 896 } 897 898 @VisibleForTesting doUpdateMobileControllers()899 void doUpdateMobileControllers() { 900 List<SubscriptionInfo> subscriptions = mSubscriptionManager 901 .getCompleteActiveSubscriptionInfoList(); 902 if (subscriptions == null) { 903 subscriptions = Collections.emptyList(); 904 } 905 906 filterMobileSubscriptionInSameGroup(subscriptions); 907 908 // If there have been no relevant changes to any of the subscriptions, we can leave as is. 909 if (hasCorrectMobileControllers(subscriptions)) { 910 // Even if the controllers are correct, make sure we have the right no sims state. 911 // Such as on boot, don't need any controllers, because there are no sims, 912 // but we still need to update the no sim state. 913 updateNoSims(); 914 return; 915 } 916 synchronized (mLock) { 917 setCurrentSubscriptionsLocked(subscriptions); 918 } 919 updateNoSims(); 920 recalculateEmergency(); 921 } 922 923 @VisibleForTesting updateNoSims()924 protected void updateNoSims() { 925 boolean hasNoSubs = mHasMobileDataFeature && mMobileSignalControllers.size() == 0; 926 boolean simDetected = hasAnySim(); 927 if (hasNoSubs != mHasNoSubs || simDetected != mSimDetected) { 928 mHasNoSubs = hasNoSubs; 929 mSimDetected = simDetected; 930 mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected); 931 } 932 } 933 hasAnySim()934 private boolean hasAnySim() { 935 int simCount = mPhone.getActiveModemCount(); 936 for (int i = 0; i < simCount; i++) { 937 int state = mPhone.getSimState(i); 938 if (state != TelephonyManager.SIM_STATE_ABSENT 939 && state != TelephonyManager.SIM_STATE_UNKNOWN) { 940 return true; 941 } 942 } 943 return false; 944 } 945 946 @GuardedBy("mLock") 947 @VisibleForTesting setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions)948 void setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions) { 949 Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() { 950 @Override 951 public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) { 952 return lhs.getSimSlotIndex() == rhs.getSimSlotIndex() 953 ? lhs.getSubscriptionId() - rhs.getSubscriptionId() 954 : lhs.getSimSlotIndex() - rhs.getSimSlotIndex(); 955 } 956 }); 957 Log.i( 958 TAG, 959 String.format( 960 Locale.US, 961 "Subscriptions changed: %s", 962 createSubscriptionChangeStatement(mCurrentSubscriptions, subscriptions))); 963 mCurrentSubscriptions = subscriptions; 964 965 SparseArray<MobileSignalController> cachedControllers = 966 new SparseArray<MobileSignalController>(); 967 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 968 cachedControllers.put(mMobileSignalControllers.keyAt(i), 969 mMobileSignalControllers.valueAt(i)); 970 } 971 mMobileSignalControllers.clear(); 972 final int num = subscriptions.size(); 973 for (int i = 0; i < num; i++) { 974 int subId = subscriptions.get(i).getSubscriptionId(); 975 // If we have a copy of this controller already reuse it, otherwise make a new one. 976 if (cachedControllers.indexOfKey(subId) >= 0) { 977 mMobileSignalControllers.put(subId, cachedControllers.get(subId)); 978 cachedControllers.remove(subId); 979 } else { 980 MobileSignalController controller = mMobileFactory.createMobileSignalController( 981 mConfig, 982 mHasMobileDataFeature, 983 mPhone.createForSubscriptionId(subId), 984 this, 985 subscriptions.get(i), 986 mSubDefaults, 987 mReceiverHandler.getLooper() 988 ); 989 controller.setUserSetupComplete(mUserSetup); 990 mMobileSignalControllers.put(subId, controller); 991 if (subscriptions.get(i).getSimSlotIndex() == 0) { 992 mDefaultSignalController = controller; 993 } 994 if (mListening) { 995 controller.registerListener(); 996 } 997 } 998 } 999 if (mListening) { 1000 for (int i = 0; i < cachedControllers.size(); i++) { 1001 int key = cachedControllers.keyAt(i); 1002 if (cachedControllers.get(key) == mDefaultSignalController) { 1003 mDefaultSignalController = null; 1004 } 1005 cachedControllers.get(key).unregisterListener(); 1006 } 1007 } 1008 mCallbackHandler.setSubs(subscriptions); 1009 notifyAllListeners(); 1010 1011 // There may be new MobileSignalControllers around, make sure they get the current 1012 // inet condition and airplane mode. 1013 pushConnectivityToSignals(); 1014 updateAirplaneMode(true /* force */); 1015 } 1016 setUserSetupComplete(final boolean userSetup)1017 private void setUserSetupComplete(final boolean userSetup) { 1018 mReceiverHandler.post(() -> handleSetUserSetupComplete(userSetup)); 1019 } 1020 handleSetUserSetupComplete(boolean userSetup)1021 private void handleSetUserSetupComplete(boolean userSetup) { 1022 mUserSetup = userSetup; 1023 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1024 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 1025 controller.setUserSetupComplete(mUserSetup); 1026 } 1027 } 1028 1029 @VisibleForTesting isUserSetup()1030 boolean isUserSetup() { 1031 return mUserSetup; 1032 } 1033 1034 @VisibleForTesting hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions)1035 boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) { 1036 if (allSubscriptions.size() != mMobileSignalControllers.size()) { 1037 return false; 1038 } 1039 for (SubscriptionInfo info : allSubscriptions) { 1040 if (mMobileSignalControllers.indexOfKey(info.getSubscriptionId()) < 0) { 1041 return false; 1042 } 1043 } 1044 return true; 1045 } 1046 1047 @VisibleForTesting setNoNetworksAvailable(boolean noNetworksAvailable)1048 void setNoNetworksAvailable(boolean noNetworksAvailable) { 1049 mNoNetworksAvailable = noNetworksAvailable; 1050 } 1051 updateAirplaneMode(boolean force)1052 private void updateAirplaneMode(boolean force) { 1053 boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(), 1054 Settings.Global.AIRPLANE_MODE_ON, 0) == 1); 1055 if (airplaneMode != mAirplaneMode || force) { 1056 mAirplaneMode = airplaneMode; 1057 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1058 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 1059 mobileSignalController.setAirplaneMode(mAirplaneMode); 1060 } 1061 notifyListeners(); 1062 } 1063 } 1064 refreshLocale()1065 private void refreshLocale() { 1066 Locale current = mContext.getResources().getConfiguration().locale; 1067 if (!current.equals(mLocale)) { 1068 mLocale = current; 1069 mWifiSignalController.refreshLocale(); 1070 notifyAllListeners(); 1071 } 1072 } 1073 1074 /** 1075 * Forces update of all callbacks on both SignalClusters and 1076 * NetworkSignalChangedCallbacks. 1077 */ notifyAllListeners()1078 private void notifyAllListeners() { 1079 notifyListeners(); 1080 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1081 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 1082 mobileSignalController.notifyListeners(); 1083 } 1084 mWifiSignalController.notifyListeners(); 1085 mEthernetSignalController.notifyListeners(); 1086 } 1087 1088 /** 1089 * Notifies listeners of changes in state of to the NetworkController, but 1090 * does not notify for any info on SignalControllers, for that call 1091 * notifyAllListeners. 1092 */ notifyListeners()1093 private void notifyListeners() { 1094 mCallbackHandler.setIsAirplaneMode( 1095 new IconState( 1096 mAirplaneMode, 1097 TelephonyIcons.FLIGHT_MODE_ICON, 1098 mContext.getString(R.string.accessibility_airplane_mode))); 1099 mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected); 1100 } 1101 1102 /** 1103 * Update the Inet conditions and what network we are connected to. 1104 */ updateConnectivity()1105 private void updateConnectivity() { 1106 mConnectedTransports.clear(); 1107 mValidatedTransports.clear(); 1108 if (mLastDefaultNetworkCapabilities != null) { 1109 for (int transportType : mLastDefaultNetworkCapabilities.getTransportTypes()) { 1110 if (transportType != NetworkCapabilities.TRANSPORT_CELLULAR 1111 && transportType != NetworkCapabilities.TRANSPORT_WIFI 1112 && transportType != NetworkCapabilities.TRANSPORT_ETHERNET) { 1113 continue; 1114 } 1115 if (transportType == NetworkCapabilities.TRANSPORT_CELLULAR 1116 && Utils.tryGetWifiInfoForVcn( 1117 mConnectivityManager, mLastDefaultNetworkCapabilities) 1118 != null) { 1119 mConnectedTransports.set(NetworkCapabilities.TRANSPORT_WIFI); 1120 if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) { 1121 mValidatedTransports.set(NetworkCapabilities.TRANSPORT_WIFI); 1122 } 1123 } else { 1124 mConnectedTransports.set(transportType); 1125 if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) { 1126 mValidatedTransports.set(transportType); 1127 } 1128 } 1129 } 1130 } 1131 1132 if (mForceCellularValidated) mValidatedTransports.set(TRANSPORT_CELLULAR); 1133 1134 if (CHATTY) { 1135 Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports); 1136 Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports); 1137 } 1138 1139 mInetCondition = mValidatedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR) 1140 || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_WIFI) 1141 || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET); 1142 1143 pushConnectivityToSignals(); 1144 mNoDefaultNetwork = !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR) 1145 && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_WIFI) 1146 && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET); 1147 mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition, 1148 mNoNetworksAvailable); 1149 } 1150 1151 /** 1152 * Pushes the current connectivity state to all SignalControllers. 1153 */ pushConnectivityToSignals()1154 private void pushConnectivityToSignals() { 1155 // We want to update all the icons, all at once, for any condition change 1156 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1157 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 1158 mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 1159 } 1160 mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 1161 mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 1162 } 1163 1164 /** */ 1165 @NeverCompile dump(PrintWriter pw, String[] args)1166 public void dump(PrintWriter pw, String[] args) { 1167 pw.println("NetworkController state:"); 1168 pw.println(" mUserSetup=" + mUserSetup); 1169 1170 pw.println(" - telephony ------"); 1171 pw.print(" hasVoiceCallingFeature()="); 1172 pw.println(hasVoiceCallingFeature()); 1173 pw.println(" mListening=" + mListening); 1174 pw.println(" mActiveMobileDataSubscription=" + mActiveMobileDataSubscription); 1175 1176 pw.println(" - connectivity ------"); 1177 pw.print(" mConnectedTransports="); 1178 pw.println(mConnectedTransports); 1179 pw.print(" mValidatedTransports="); 1180 pw.println(mValidatedTransports); 1181 pw.print(" mInetCondition="); 1182 pw.println(mInetCondition); 1183 pw.print(" mAirplaneMode="); 1184 pw.println(mAirplaneMode); 1185 pw.print(" mLocale="); 1186 pw.println(mLocale); 1187 pw.print(" mLastServiceState="); 1188 pw.println(mLastServiceState); 1189 pw.print(" mIsEmergency="); 1190 pw.println(mIsEmergency); 1191 pw.print(" mEmergencySource="); 1192 pw.println(emergencyToString(mEmergencySource)); 1193 1194 pw.println(" - DefaultNetworkCallback -----"); 1195 int size = 0; 1196 for (int i = 0; i < HISTORY_SIZE; i++) { 1197 if (mHistory[i] != null) { 1198 size++; 1199 } 1200 } 1201 for (int i = mHistoryIndex + HISTORY_SIZE - 1; 1202 i >= mHistoryIndex + HISTORY_SIZE - size; i--) { 1203 pw.println(" Previous NetworkCallback(" + (mHistoryIndex + HISTORY_SIZE - i) + "): " 1204 + mHistory[i & (HISTORY_SIZE - 1)]); 1205 } 1206 1207 pw.println(" - config ------"); 1208 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1209 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 1210 mobileSignalController.dump(pw); 1211 } 1212 mWifiSignalController.dump(pw); 1213 1214 mEthernetSignalController.dump(pw); 1215 1216 mAccessPoints.dump(pw); 1217 1218 mCallbackHandler.dump(pw); 1219 } 1220 emergencyToString(int emergencySource)1221 private static String emergencyToString(int emergencySource) { 1222 if (emergencySource > EMERGENCY_NO_SUB) { 1223 return "ASSUMED_VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) 1224 + ")"; 1225 } else if (emergencySource > EMERGENCY_NO_SUB) { 1226 return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")"; 1227 } else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) { 1228 return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")"; 1229 } else if (emergencySource > EMERGENCY_FIRST_CONTROLLER) { 1230 return "FIRST_CONTROLLER(" + (emergencySource - EMERGENCY_FIRST_CONTROLLER) + ")"; 1231 } else if (emergencySource == EMERGENCY_NO_CONTROLLERS) { 1232 return "NO_CONTROLLERS"; 1233 } 1234 return "UNKNOWN_SOURCE"; 1235 } 1236 1237 private boolean mDemoInetCondition; 1238 1239 @Override onDemoModeStarted()1240 public void onDemoModeStarted() { 1241 if (DEBUG) Log.d(TAG, "Entering demo mode"); 1242 unregisterListeners(); 1243 mDemoInetCondition = mInetCondition; 1244 } 1245 1246 @Override onDemoModeFinished()1247 public void onDemoModeFinished() { 1248 if (DEBUG) Log.d(TAG, "Exiting demo mode"); 1249 // Update what MobileSignalControllers, because they may change 1250 // to set the number of sim slots. 1251 updateMobileControllers(); 1252 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1253 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 1254 controller.resetLastState(); 1255 } 1256 mWifiSignalController.resetLastState(); 1257 mReceiverHandler.post(mRegisterListeners); 1258 notifyAllListeners(); 1259 } 1260 1261 @Override dispatchDemoCommand(String command, Bundle args)1262 public void dispatchDemoCommand(String command, Bundle args) { 1263 if (!mDemoModeController.isInDemoMode()) { 1264 return; 1265 } 1266 1267 String airplane = args.getString("airplane"); 1268 if (airplane != null) { 1269 boolean show = airplane.equals("show"); 1270 mCallbackHandler.setIsAirplaneMode( 1271 new IconState( 1272 show, 1273 TelephonyIcons.FLIGHT_MODE_ICON, 1274 mContext.getString(R.string.accessibility_airplane_mode))); 1275 } 1276 String fully = args.getString("fully"); 1277 if (fully != null) { 1278 mDemoInetCondition = Boolean.parseBoolean(fully); 1279 BitSet connected = new BitSet(); 1280 1281 if (mDemoInetCondition) { 1282 connected.set(mWifiSignalController.mTransportType); 1283 } 1284 mWifiSignalController.updateConnectivity(connected, connected); 1285 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1286 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 1287 if (mDemoInetCondition) { 1288 connected.set(controller.mTransportType); 1289 } 1290 controller.updateConnectivity(connected, connected); 1291 } 1292 } 1293 String sims = args.getString("sims"); 1294 if (sims != null) { 1295 int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8); 1296 List<SubscriptionInfo> subs = new ArrayList<>(); 1297 if (num != mMobileSignalControllers.size()) { 1298 mMobileSignalControllers.clear(); 1299 int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); 1300 for (int i = start /* get out of normal index range */; i < start + num; i++) { 1301 subs.add(addDemoModeSignalController(i, i)); 1302 } 1303 mCallbackHandler.setSubs(subs); 1304 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1305 int key = mMobileSignalControllers.keyAt(i); 1306 MobileSignalController controller = mMobileSignalControllers.get(key); 1307 controller.notifyListeners(); 1308 } 1309 } 1310 } 1311 String nosim = args.getString("nosim"); 1312 if (nosim != null) { 1313 mHasNoSubs = nosim.equals("show"); 1314 mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected); 1315 } 1316 String mobile = args.getString("mobile"); 1317 if (mobile != null) { 1318 boolean show = mobile.equals("show"); 1319 String datatype = args.getString("datatype"); 1320 String slotString = args.getString("slot"); 1321 int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString); 1322 slot = MathUtils.constrain(slot, 0, 8); 1323 String carrierIdString = args.getString("carrierid"); 1324 int carrierId = TextUtils.isEmpty(carrierIdString) ? 0 1325 : Integer.parseInt(carrierIdString); 1326 // Ensure we have enough sim slots 1327 // TODO(b/336357360): This is the origination of the infinite loop bug, for those 1328 // following along at home. 1329 List<SubscriptionInfo> subs = new ArrayList<>(); 1330 while (mMobileSignalControllers.size() <= slot) { 1331 int nextSlot = mMobileSignalControllers.size(); 1332 subs.add(addDemoModeSignalController(nextSlot, nextSlot)); 1333 } 1334 if (!subs.isEmpty()) { 1335 mCallbackHandler.setSubs(subs); 1336 } 1337 // Hack to index linearly for easy use. 1338 MobileSignalController controller = mMobileSignalControllers.valueAt(slot); 1339 if (carrierId != 0) { 1340 controller.getState().setCarrierId(carrierId); 1341 } 1342 controller.getState().dataSim = datatype != null; 1343 controller.getState().isDefault = datatype != null; 1344 controller.getState().dataConnected = datatype != null; 1345 if (datatype != null) { 1346 controller.getState().iconGroup = 1347 datatype.equals("1x") ? TelephonyIcons.ONE_X : 1348 datatype.equals("3g") ? TelephonyIcons.THREE_G : 1349 datatype.equals("4g") ? TelephonyIcons.FOUR_G : 1350 datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS : 1351 datatype.equals("5g") ? TelephonyIcons.NR_5G : 1352 datatype.equals("5ge") ? TelephonyIcons.LTE_CA_5G_E : 1353 datatype.equals("5g+") ? TelephonyIcons.NR_5G_PLUS : 1354 datatype.equals("e") ? TelephonyIcons.E : 1355 datatype.equals("g") ? TelephonyIcons.G : 1356 datatype.equals("h") ? TelephonyIcons.H : 1357 datatype.equals("h+") ? TelephonyIcons.H_PLUS : 1358 datatype.equals("lte") ? TelephonyIcons.LTE : 1359 datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS : 1360 datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED : 1361 datatype.equals("not") ? TelephonyIcons.NOT_DEFAULT_DATA : 1362 TelephonyIcons.UNKNOWN; 1363 } 1364 if (args.containsKey("roam")) { 1365 controller.getState().roaming = "show".equals(args.getString("roam")); 1366 } 1367 String level = args.getString("level"); 1368 if (level != null) { 1369 controller.getState().level = level.equals("null") ? -1 1370 : Math.min(Integer.parseInt(level), 1371 CellSignalStrength.getNumSignalStrengthLevels()); 1372 controller.getState().connected = controller.getState().level >= 0; 1373 } 1374 if (args.containsKey("inflate")) { 1375 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1376 mMobileSignalControllers.valueAt(i).mInflateSignalStrengths = 1377 "true".equals(args.getString("inflate")); 1378 } 1379 } 1380 String activity = args.getString("activity"); 1381 if (activity != null) { 1382 controller.getState().dataConnected = true; 1383 switch (activity) { 1384 case "inout": 1385 controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT); 1386 break; 1387 case "in": 1388 controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN); 1389 break; 1390 case "out": 1391 controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT); 1392 break; 1393 default: 1394 controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE); 1395 break; 1396 } 1397 } else { 1398 controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE); 1399 } 1400 controller.getState().enabled = show; 1401 controller.notifyListeners(); 1402 } 1403 String carrierNetworkChange = args.getString("carriernetworkchange"); 1404 if (carrierNetworkChange != null) { 1405 boolean show = carrierNetworkChange.equals("show"); 1406 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 1407 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 1408 controller.setCarrierNetworkChangeMode(show); 1409 } 1410 } 1411 } 1412 1413 @Override demoCommands()1414 public List<String> demoCommands() { 1415 List<String> s = new ArrayList<>(); 1416 s.add(DemoMode.COMMAND_NETWORK); 1417 return s; 1418 } 1419 recordLastNetworkCallback(String callback)1420 private void recordLastNetworkCallback(String callback) { 1421 mHistory[mHistoryIndex] = callback; 1422 mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE; 1423 } 1424 addDemoModeSignalController(int id, int simSlotIndex)1425 private SubscriptionInfo addDemoModeSignalController(int id, int simSlotIndex) { 1426 SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0, 1427 null, null, null, "", false, null, null); 1428 1429 MobileSignalController controller = mMobileFactory.createMobileSignalController( 1430 mConfig, 1431 mHasMobileDataFeature, 1432 mPhone.createForSubscriptionId(info.getSubscriptionId()), 1433 this, 1434 info, 1435 mSubDefaults, 1436 mReceiverHandler.getLooper() 1437 ); 1438 1439 mMobileSignalControllers.put(id, controller); 1440 controller.getState().userSetup = true; 1441 return info; 1442 } 1443 1444 /** */ isRadioOn()1445 public boolean isRadioOn() { 1446 return !mAirplaneMode; 1447 } 1448 1449 private class SubListener extends OnSubscriptionsChangedListener { SubListener(Looper looper)1450 SubListener(Looper looper) { 1451 super(looper); 1452 } 1453 1454 @Override onSubscriptionsChanged()1455 public void onSubscriptionsChanged() { 1456 updateMobileControllers(); 1457 } 1458 } 1459 1460 /** 1461 * Used to register listeners from the BG Looper, this way the PhoneStateListeners that 1462 * get created will also run on the BG Looper. 1463 */ 1464 private final Runnable mRegisterListeners = () -> registerListeners(); 1465 1466 /** 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)1467 private static String createSubscriptionChangeStatement( 1468 final @Nullable List<SubscriptionInfo> oldSubscriptions, 1469 final @Nullable List<SubscriptionInfo> newSubscriptions) { 1470 return String.format( 1471 Locale.US, 1472 "old=%s, new=%s", 1473 toSubscriptionIds(oldSubscriptions), 1474 toSubscriptionIds(newSubscriptions)); 1475 } 1476 1477 /** Returns to a list of subscription IDs for the given list of {@link SubscriptionInfo} */ 1478 @Nullable toSubscriptionIds( final @Nullable List<SubscriptionInfo> subscriptions)1479 private static List<Integer> toSubscriptionIds( 1480 final @Nullable List<SubscriptionInfo> subscriptions) { 1481 return subscriptions != null ? subscriptions.stream().map( 1482 SubscriptionInfo::getSubscriptionId).collect(Collectors.toList()) : null; 1483 } 1484 } 1485