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