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