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