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 android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.content.res.Configuration; 24 import android.content.res.Resources; 25 import android.net.ConnectivityManager; 26 import android.net.NetworkCapabilities; 27 import android.net.NetworkScoreManager; 28 import android.net.wifi.WifiManager; 29 import android.os.AsyncTask; 30 import android.os.Bundle; 31 import android.os.Handler; 32 import android.os.Looper; 33 import android.provider.Settings; 34 import android.telephony.ServiceState; 35 import android.telephony.SignalStrength; 36 import android.telephony.SubscriptionInfo; 37 import android.telephony.SubscriptionManager; 38 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 39 import android.telephony.TelephonyManager; 40 import android.text.TextUtils; 41 import android.util.Log; 42 import android.util.MathUtils; 43 import android.util.SparseArray; 44 45 import com.android.internal.annotations.VisibleForTesting; 46 import com.android.internal.telephony.PhoneConstants; 47 import com.android.internal.telephony.TelephonyIntents; 48 import com.android.settingslib.net.DataUsageController; 49 import com.android.systemui.ConfigurationChangedReceiver; 50 import com.android.systemui.DemoMode; 51 import com.android.systemui.Dumpable; 52 import com.android.systemui.R; 53 import com.android.systemui.settings.CurrentUserTracker; 54 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; 55 56 import java.io.FileDescriptor; 57 import java.io.PrintWriter; 58 import java.util.ArrayList; 59 import java.util.BitSet; 60 import java.util.Collections; 61 import java.util.Comparator; 62 import java.util.HashMap; 63 import java.util.List; 64 import java.util.Locale; 65 import java.util.Map; 66 67 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; 68 69 /** Platform implementation of the network controller. **/ 70 public class NetworkControllerImpl extends BroadcastReceiver 71 implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider, 72 ConfigurationChangedReceiver, Dumpable { 73 // debug 74 static final String TAG = "NetworkController"; 75 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 76 // additional diagnostics, but not logspew 77 static final boolean CHATTY = Log.isLoggable(TAG + "Chat", Log.DEBUG); 78 79 private static final int EMERGENCY_NO_CONTROLLERS = 0; 80 private static final int EMERGENCY_FIRST_CONTROLLER = 100; 81 private static final int EMERGENCY_VOICE_CONTROLLER = 200; 82 private static final int EMERGENCY_NO_SUB = 300; 83 private static final int EMERGENCY_ASSUMED_VOICE_CONTROLLER = 400; 84 85 private final Context mContext; 86 private final TelephonyManager mPhone; 87 private final WifiManager mWifiManager; 88 private final ConnectivityManager mConnectivityManager; 89 private final SubscriptionManager mSubscriptionManager; 90 private final boolean mHasMobileDataFeature; 91 private final SubscriptionDefaults mSubDefaults; 92 private final DataSaverController mDataSaverController; 93 private final CurrentUserTracker mUserTracker; 94 private Config mConfig; 95 private final NetworkScoreManager mNetworkScoreManager; 96 97 // Subcontrollers. 98 @VisibleForTesting 99 final WifiSignalController mWifiSignalController; 100 101 @VisibleForTesting 102 final EthernetSignalController mEthernetSignalController; 103 104 @VisibleForTesting 105 final SparseArray<MobileSignalController> mMobileSignalControllers = new SparseArray<>(); 106 // When no SIMs are around at setup, and one is added later, it seems to default to the first 107 // SIM for most actions. This may be null if there aren't any SIMs around. 108 private MobileSignalController mDefaultSignalController; 109 private final AccessPointControllerImpl mAccessPoints; 110 private final DataUsageController mDataUsageController; 111 112 private boolean mInetCondition; // Used for Logging and demo. 113 114 // BitSets indicating which network transport types (e.g., TRANSPORT_WIFI, TRANSPORT_MOBILE) are 115 // connected and validated, respectively. 116 private final BitSet mConnectedTransports = new BitSet(); 117 private final BitSet mValidatedTransports = new BitSet(); 118 119 // States that don't belong to a subcontroller. 120 private boolean mAirplaneMode = false; 121 private boolean mHasNoSims; 122 private Locale mLocale = null; 123 // This list holds our ordering. 124 private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>(); 125 126 @VisibleForTesting 127 boolean mListening; 128 129 // The current user ID. 130 private int mCurrentUserId; 131 132 private OnSubscriptionsChangedListener mSubscriptionListener; 133 134 // Handler that all broadcasts are received on. 135 private final Handler mReceiverHandler; 136 // Handler that all callbacks are made on. 137 private final CallbackHandler mCallbackHandler; 138 139 private int mEmergencySource; 140 private boolean mIsEmergency; 141 142 @VisibleForTesting 143 ServiceState mLastServiceState; 144 private boolean mUserSetup; 145 146 /** 147 * Construct this controller object and register for updates. 148 */ 149 public NetworkControllerImpl(Context context, Looper bgLooper, 150 DeviceProvisionedController deviceProvisionedController) { 151 this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE), 152 context.getSystemService(NetworkScoreManager.class), 153 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE), 154 (WifiManager) context.getSystemService(Context.WIFI_SERVICE), 155 SubscriptionManager.from(context), 156 Config.readConfig(context), 157 bgLooper, 158 new CallbackHandler(), 159 new AccessPointControllerImpl(context, bgLooper), 160 new DataUsageController(context), 161 new SubscriptionDefaults(), 162 deviceProvisionedController); 163 mReceiverHandler.post(mRegisterListeners); 164 } 165 166 @VisibleForTesting 167 NetworkControllerImpl(Context context, ConnectivityManager connectivityManager, 168 NetworkScoreManager networkScoreManager, 169 TelephonyManager telephonyManager, 170 WifiManager wifiManager, 171 SubscriptionManager subManager, 172 Config config, 173 Looper bgLooper, 174 CallbackHandler callbackHandler, 175 AccessPointControllerImpl accessPointController, 176 DataUsageController dataUsageController, 177 SubscriptionDefaults defaultsHandler, 178 DeviceProvisionedController deviceProvisionedController) { 179 mContext = context; 180 mConfig = config; 181 mReceiverHandler = new Handler(bgLooper); 182 mCallbackHandler = callbackHandler; 183 mDataSaverController = new DataSaverControllerImpl(context); 184 185 mSubscriptionManager = subManager; 186 mSubDefaults = defaultsHandler; 187 mConnectivityManager = connectivityManager; 188 mHasMobileDataFeature = 189 mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); 190 191 // telephony 192 mPhone = telephonyManager; 193 194 // wifi 195 mWifiManager = wifiManager; 196 mNetworkScoreManager = networkScoreManager; 197 198 mLocale = mContext.getResources().getConfiguration().locale; 199 mAccessPoints = accessPointController; 200 mDataUsageController = dataUsageController; 201 mDataUsageController.setNetworkController(this); 202 // TODO: Find a way to move this into DataUsageController. 203 mDataUsageController.setCallback(new DataUsageController.Callback() { 204 @Override 205 public void onMobileDataEnabled(boolean enabled) { 206 mCallbackHandler.setMobileDataEnabled(enabled); 207 } 208 }); 209 mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature, 210 mCallbackHandler, this, mNetworkScoreManager); 211 212 mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this); 213 214 // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it 215 updateAirplaneMode(true /* force callback */); 216 mUserTracker = new CurrentUserTracker(mContext) { 217 @Override 218 public void onUserSwitched(int newUserId) { 219 NetworkControllerImpl.this.onUserSwitched(newUserId); 220 } 221 }; 222 mUserTracker.startTracking(); 223 deviceProvisionedController.addCallback(new DeviceProvisionedListener() { 224 @Override 225 public void onUserSetupChanged() { 226 setUserSetupComplete(deviceProvisionedController.isUserSetup( 227 deviceProvisionedController.getCurrentUser())); 228 } 229 }); 230 } 231 232 public DataSaverController getDataSaverController() { 233 return mDataSaverController; 234 } 235 236 private void registerListeners() { 237 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 238 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 239 mobileSignalController.registerListener(); 240 } 241 if (mSubscriptionListener == null) { 242 mSubscriptionListener = new SubListener(); 243 } 244 mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener); 245 246 // broadcasts 247 IntentFilter filter = new IntentFilter(); 248 filter.addAction(WifiManager.RSSI_CHANGED_ACTION); 249 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 250 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 251 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 252 filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); 253 filter.addAction(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); 254 filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); 255 filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); 256 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 257 filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); 258 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 259 mContext.registerReceiver(this, filter, null, mReceiverHandler); 260 mListening = true; 261 262 updateMobileControllers(); 263 } 264 265 private void unregisterListeners() { 266 mListening = false; 267 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 268 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 269 mobileSignalController.unregisterListener(); 270 } 271 mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener); 272 mContext.unregisterReceiver(this); 273 } 274 275 public int getConnectedWifiLevel() { 276 return mWifiSignalController.getState().level; 277 } 278 279 @Override 280 public AccessPointController getAccessPointController() { 281 return mAccessPoints; 282 } 283 284 @Override 285 public DataUsageController getMobileDataController() { 286 return mDataUsageController; 287 } 288 289 public void addEmergencyListener(EmergencyListener listener) { 290 mCallbackHandler.setListening(listener, true); 291 mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly()); 292 } 293 294 public void removeEmergencyListener(EmergencyListener listener) { 295 mCallbackHandler.setListening(listener, false); 296 } 297 298 public boolean hasMobileDataFeature() { 299 return mHasMobileDataFeature; 300 } 301 302 public boolean hasVoiceCallingFeature() { 303 return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE; 304 } 305 306 private MobileSignalController getDataController() { 307 int dataSubId = mSubDefaults.getDefaultDataSubId(); 308 if (!SubscriptionManager.isValidSubscriptionId(dataSubId)) { 309 if (DEBUG) Log.e(TAG, "No data sim selected"); 310 return mDefaultSignalController; 311 } 312 if (mMobileSignalControllers.indexOfKey(dataSubId) >= 0) { 313 return mMobileSignalControllers.get(dataSubId); 314 } 315 if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + dataSubId); 316 return mDefaultSignalController; 317 } 318 319 public String getMobileDataNetworkName() { 320 MobileSignalController controller = getDataController(); 321 return controller != null ? controller.getState().networkNameData : ""; 322 } 323 324 public boolean isEmergencyOnly() { 325 if (mMobileSignalControllers.size() == 0) { 326 // When there are no active subscriptions, determine emengency state from last 327 // broadcast. 328 mEmergencySource = EMERGENCY_NO_CONTROLLERS; 329 return mLastServiceState != null && mLastServiceState.isEmergencyOnly(); 330 } 331 int voiceSubId = mSubDefaults.getDefaultVoiceSubId(); 332 if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) { 333 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 334 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 335 if (!mobileSignalController.getState().isEmergency) { 336 mEmergencySource = EMERGENCY_FIRST_CONTROLLER 337 + mobileSignalController.mSubscriptionInfo.getSubscriptionId(); 338 if (DEBUG) Log.d(TAG, "Found emergency " + mobileSignalController.mTag); 339 return false; 340 } 341 } 342 } 343 if (mMobileSignalControllers.indexOfKey(voiceSubId) >= 0) { 344 mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId; 345 if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId); 346 return mMobileSignalControllers.get(voiceSubId).getState().isEmergency; 347 } 348 // If we have the wrong subId but there is only one sim anyway, assume it should be the 349 // default. 350 if (mMobileSignalControllers.size() == 1) { 351 mEmergencySource = EMERGENCY_ASSUMED_VOICE_CONTROLLER 352 + mMobileSignalControllers.keyAt(0); 353 if (DEBUG) Log.d(TAG, "Getting assumed emergency from " 354 + mMobileSignalControllers.keyAt(0)); 355 return mMobileSignalControllers.valueAt(0).getState().isEmergency; 356 } 357 if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId); 358 mEmergencySource = EMERGENCY_NO_SUB + voiceSubId; 359 // Something is wrong, better assume we can't make calls... 360 return true; 361 } 362 363 /** 364 * Emergency status may have changed (triggered by MobileSignalController), 365 * so we should recheck and send out the state to listeners. 366 */ 367 void recalculateEmergency() { 368 mIsEmergency = isEmergencyOnly(); 369 mCallbackHandler.setEmergencyCallsOnly(mIsEmergency); 370 } 371 372 public void addCallback(SignalCallback cb) { 373 cb.setSubs(mCurrentSubscriptions); 374 cb.setIsAirplaneMode(new IconState(mAirplaneMode, 375 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext)); 376 cb.setNoSims(mHasNoSims); 377 mWifiSignalController.notifyListeners(cb); 378 mEthernetSignalController.notifyListeners(cb); 379 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 380 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 381 mobileSignalController.notifyListeners(cb); 382 } 383 mCallbackHandler.setListening(cb, true); 384 } 385 386 @Override 387 public void removeCallback(SignalCallback cb) { 388 mCallbackHandler.setListening(cb, false); 389 } 390 391 @Override 392 public void setWifiEnabled(final boolean enabled) { 393 new AsyncTask<Void, Void, Void>() { 394 @Override 395 protected Void doInBackground(Void... args) { 396 // Disable tethering if enabling Wifi 397 final int wifiApState = mWifiManager.getWifiApState(); 398 if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) || 399 (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) { 400 mWifiManager.setWifiApEnabled(null, false); 401 } 402 403 mWifiManager.setWifiEnabled(enabled); 404 return null; 405 } 406 }.execute(); 407 } 408 409 private void onUserSwitched(int newUserId) { 410 mCurrentUserId = newUserId; 411 mAccessPoints.onUserSwitched(newUserId); 412 updateConnectivity(); 413 } 414 415 @Override 416 public void onReceive(Context context, Intent intent) { 417 if (CHATTY) { 418 Log.d(TAG, "onReceive: intent=" + intent); 419 } 420 final String action = intent.getAction(); 421 if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) || 422 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) { 423 updateConnectivity(); 424 } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 425 refreshLocale(); 426 updateAirplaneMode(false); 427 } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED)) { 428 // We are using different subs now, we might be able to make calls. 429 recalculateEmergency(); 430 } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) { 431 // Notify every MobileSignalController so they can know whether they are the 432 // data sim or not. 433 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 434 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 435 controller.handleBroadcast(intent); 436 } 437 } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { 438 // Might have different subscriptions now. 439 updateMobileControllers(); 440 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) { 441 mLastServiceState = ServiceState.newFromBundle(intent.getExtras()); 442 if (mMobileSignalControllers.size() == 0) { 443 // If none of the subscriptions are active, we might need to recalculate 444 // emergency state. 445 recalculateEmergency(); 446 } 447 } else { 448 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, 449 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 450 if (SubscriptionManager.isValidSubscriptionId(subId)) { 451 if (mMobileSignalControllers.indexOfKey(subId) >= 0) { 452 mMobileSignalControllers.get(subId).handleBroadcast(intent); 453 } else { 454 // Can't find this subscription... We must be out of date. 455 updateMobileControllers(); 456 } 457 } else { 458 // No sub id, must be for the wifi. 459 mWifiSignalController.handleBroadcast(intent); 460 } 461 } 462 } 463 464 public void onConfigurationChanged(Configuration newConfig) { 465 mConfig = Config.readConfig(mContext); 466 mReceiverHandler.post(new Runnable() { 467 @Override 468 public void run() { 469 handleConfigurationChanged(); 470 } 471 }); 472 } 473 474 @VisibleForTesting 475 void handleConfigurationChanged() { 476 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 477 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 478 controller.setConfiguration(mConfig); 479 } 480 refreshLocale(); 481 } 482 483 private void updateMobileControllers() { 484 if (!mListening) { 485 return; 486 } 487 doUpdateMobileControllers(); 488 } 489 490 @VisibleForTesting 491 void doUpdateMobileControllers() { 492 List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList(); 493 if (subscriptions == null) { 494 subscriptions = Collections.emptyList(); 495 } 496 // If there have been no relevant changes to any of the subscriptions, we can leave as is. 497 if (hasCorrectMobileControllers(subscriptions)) { 498 // Even if the controllers are correct, make sure we have the right no sims state. 499 // Such as on boot, don't need any controllers, because there are no sims, 500 // but we still need to update the no sim state. 501 updateNoSims(); 502 return; 503 } 504 setCurrentSubscriptions(subscriptions); 505 updateNoSims(); 506 recalculateEmergency(); 507 } 508 509 @VisibleForTesting 510 protected void updateNoSims() { 511 boolean hasNoSims = mHasMobileDataFeature && mMobileSignalControllers.size() == 0; 512 if (hasNoSims != mHasNoSims) { 513 mHasNoSims = hasNoSims; 514 mCallbackHandler.setNoSims(mHasNoSims); 515 } 516 } 517 518 @VisibleForTesting 519 void setCurrentSubscriptions(List<SubscriptionInfo> subscriptions) { 520 Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() { 521 @Override 522 public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) { 523 return lhs.getSimSlotIndex() == rhs.getSimSlotIndex() 524 ? lhs.getSubscriptionId() - rhs.getSubscriptionId() 525 : lhs.getSimSlotIndex() - rhs.getSimSlotIndex(); 526 } 527 }); 528 mCurrentSubscriptions = subscriptions; 529 530 SparseArray<MobileSignalController> cachedControllers = 531 new SparseArray<MobileSignalController>(); 532 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 533 cachedControllers.put(mMobileSignalControllers.keyAt(i), 534 mMobileSignalControllers.valueAt(i)); 535 } 536 mMobileSignalControllers.clear(); 537 final int num = subscriptions.size(); 538 for (int i = 0; i < num; i++) { 539 int subId = subscriptions.get(i).getSubscriptionId(); 540 // If we have a copy of this controller already reuse it, otherwise make a new one. 541 if (cachedControllers.indexOfKey(subId) >= 0) { 542 mMobileSignalControllers.put(subId, cachedControllers.get(subId)); 543 cachedControllers.remove(subId); 544 } else { 545 MobileSignalController controller = new MobileSignalController(mContext, mConfig, 546 mHasMobileDataFeature, mPhone, mCallbackHandler, 547 this, subscriptions.get(i), mSubDefaults, mReceiverHandler.getLooper()); 548 controller.setUserSetupComplete(mUserSetup); 549 mMobileSignalControllers.put(subId, controller); 550 if (subscriptions.get(i).getSimSlotIndex() == 0) { 551 mDefaultSignalController = controller; 552 } 553 if (mListening) { 554 controller.registerListener(); 555 } 556 } 557 } 558 if (mListening) { 559 for (int i = 0; i < cachedControllers.size(); i++) { 560 int key = cachedControllers.keyAt(i); 561 if (cachedControllers.get(key) == mDefaultSignalController) { 562 mDefaultSignalController = null; 563 } 564 cachedControllers.get(key).unregisterListener(); 565 } 566 } 567 mCallbackHandler.setSubs(subscriptions); 568 notifyAllListeners(); 569 570 // There may be new MobileSignalControllers around, make sure they get the current 571 // inet condition and airplane mode. 572 pushConnectivityToSignals(); 573 updateAirplaneMode(true /* force */); 574 } 575 576 private void setUserSetupComplete(final boolean userSetup) { 577 mReceiverHandler.post(() -> handleSetUserSetupComplete(userSetup)); 578 } 579 580 private void handleSetUserSetupComplete(boolean userSetup) { 581 mUserSetup = userSetup; 582 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 583 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 584 controller.setUserSetupComplete(mUserSetup); 585 } 586 } 587 588 @VisibleForTesting 589 boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) { 590 if (allSubscriptions.size() != mMobileSignalControllers.size()) { 591 return false; 592 } 593 for (SubscriptionInfo info : allSubscriptions) { 594 if (mMobileSignalControllers.indexOfKey(info.getSubscriptionId()) < 0) { 595 return false; 596 } 597 } 598 return true; 599 } 600 601 private void updateAirplaneMode(boolean force) { 602 boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(), 603 Settings.Global.AIRPLANE_MODE_ON, 0) == 1); 604 if (airplaneMode != mAirplaneMode || force) { 605 mAirplaneMode = airplaneMode; 606 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 607 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 608 mobileSignalController.setAirplaneMode(mAirplaneMode); 609 } 610 notifyListeners(); 611 } 612 } 613 614 private void refreshLocale() { 615 Locale current = mContext.getResources().getConfiguration().locale; 616 if (!current.equals(mLocale)) { 617 mLocale = current; 618 notifyAllListeners(); 619 } 620 } 621 622 /** 623 * Forces update of all callbacks on both SignalClusters and 624 * NetworkSignalChangedCallbacks. 625 */ 626 private void notifyAllListeners() { 627 notifyListeners(); 628 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 629 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 630 mobileSignalController.notifyListeners(); 631 } 632 mWifiSignalController.notifyListeners(); 633 mEthernetSignalController.notifyListeners(); 634 } 635 636 /** 637 * Notifies listeners of changes in state of to the NetworkController, but 638 * does not notify for any info on SignalControllers, for that call 639 * notifyAllListeners. 640 */ 641 private void notifyListeners() { 642 mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode, 643 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext)); 644 mCallbackHandler.setNoSims(mHasNoSims); 645 } 646 647 /** 648 * Update the Inet conditions and what network we are connected to. 649 */ 650 private void updateConnectivity() { 651 mConnectedTransports.clear(); 652 mValidatedTransports.clear(); 653 for (NetworkCapabilities nc : 654 mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) { 655 for (int transportType : nc.getTransportTypes()) { 656 mConnectedTransports.set(transportType); 657 if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) { 658 mValidatedTransports.set(transportType); 659 } 660 } 661 } 662 663 if (CHATTY) { 664 Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports); 665 Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports); 666 } 667 668 mInetCondition = !mValidatedTransports.isEmpty(); 669 670 pushConnectivityToSignals(); 671 } 672 673 /** 674 * Pushes the current connectivity state to all SignalControllers. 675 */ 676 private void pushConnectivityToSignals() { 677 // We want to update all the icons, all at once, for any condition change 678 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 679 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 680 mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 681 } 682 mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 683 mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); 684 } 685 686 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 687 pw.println("NetworkController state:"); 688 689 pw.println(" - telephony ------"); 690 pw.print(" hasVoiceCallingFeature()="); 691 pw.println(hasVoiceCallingFeature()); 692 693 pw.println(" - connectivity ------"); 694 pw.print(" mConnectedTransports="); 695 pw.println(mConnectedTransports); 696 pw.print(" mValidatedTransports="); 697 pw.println(mValidatedTransports); 698 pw.print(" mInetCondition="); 699 pw.println(mInetCondition); 700 pw.print(" mAirplaneMode="); 701 pw.println(mAirplaneMode); 702 pw.print(" mLocale="); 703 pw.println(mLocale); 704 pw.print(" mLastServiceState="); 705 pw.println(mLastServiceState); 706 pw.print(" mIsEmergency="); 707 pw.println(mIsEmergency); 708 pw.print(" mEmergencySource="); 709 pw.println(emergencyToString(mEmergencySource)); 710 711 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 712 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); 713 mobileSignalController.dump(pw); 714 } 715 mWifiSignalController.dump(pw); 716 717 mEthernetSignalController.dump(pw); 718 719 mAccessPoints.dump(pw); 720 } 721 722 private static final String emergencyToString(int emergencySource) { 723 if (emergencySource > EMERGENCY_NO_SUB) { 724 return "ASSUMED_VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) 725 + ")"; 726 } else if (emergencySource > EMERGENCY_NO_SUB) { 727 return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")"; 728 } else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) { 729 return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")"; 730 } else if (emergencySource > EMERGENCY_FIRST_CONTROLLER) { 731 return "FIRST_CONTROLLER(" + (emergencySource - EMERGENCY_FIRST_CONTROLLER) + ")"; 732 } else if (emergencySource == EMERGENCY_NO_CONTROLLERS) { 733 return "NO_CONTROLLERS"; 734 } 735 return "UNKNOWN_SOURCE"; 736 } 737 738 private boolean mDemoMode; 739 private boolean mDemoInetCondition; 740 private WifiSignalController.WifiState mDemoWifiState; 741 742 @Override 743 public void dispatchDemoCommand(String command, Bundle args) { 744 if (!mDemoMode && command.equals(COMMAND_ENTER)) { 745 if (DEBUG) Log.d(TAG, "Entering demo mode"); 746 unregisterListeners(); 747 mDemoMode = true; 748 mDemoInetCondition = mInetCondition; 749 mDemoWifiState = mWifiSignalController.getState(); 750 mDemoWifiState.ssid = "DemoMode"; 751 } else if (mDemoMode && command.equals(COMMAND_EXIT)) { 752 if (DEBUG) Log.d(TAG, "Exiting demo mode"); 753 mDemoMode = false; 754 // Update what MobileSignalControllers, because they may change 755 // to set the number of sim slots. 756 updateMobileControllers(); 757 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 758 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 759 controller.resetLastState(); 760 } 761 mWifiSignalController.resetLastState(); 762 mReceiverHandler.post(mRegisterListeners); 763 notifyAllListeners(); 764 } else if (mDemoMode && command.equals(COMMAND_NETWORK)) { 765 String airplane = args.getString("airplane"); 766 if (airplane != null) { 767 boolean show = airplane.equals("show"); 768 mCallbackHandler.setIsAirplaneMode(new IconState(show, 769 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, 770 mContext)); 771 } 772 String fully = args.getString("fully"); 773 if (fully != null) { 774 mDemoInetCondition = Boolean.parseBoolean(fully); 775 BitSet connected = new BitSet(); 776 777 if (mDemoInetCondition) { 778 connected.set(mWifiSignalController.mTransportType); 779 } 780 mWifiSignalController.updateConnectivity(connected, connected); 781 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 782 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 783 if (mDemoInetCondition) { 784 connected.set(controller.mTransportType); 785 } 786 controller.updateConnectivity(connected, connected); 787 } 788 } 789 String wifi = args.getString("wifi"); 790 if (wifi != null) { 791 boolean show = wifi.equals("show"); 792 String level = args.getString("level"); 793 if (level != null) { 794 mDemoWifiState.level = level.equals("null") ? -1 795 : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1); 796 mDemoWifiState.connected = mDemoWifiState.level >= 0; 797 } 798 String activity = args.getString("activity"); 799 if (activity != null) { 800 switch (activity) { 801 case "inout": 802 mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_INOUT); 803 break; 804 case "in": 805 mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_IN); 806 break; 807 case "out": 808 mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_OUT); 809 break; 810 default: 811 mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE); 812 break; 813 } 814 } else { 815 mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE); 816 } 817 mDemoWifiState.enabled = show; 818 mWifiSignalController.notifyListeners(); 819 } 820 String sims = args.getString("sims"); 821 if (sims != null) { 822 int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8); 823 List<SubscriptionInfo> subs = new ArrayList<>(); 824 if (num != mMobileSignalControllers.size()) { 825 mMobileSignalControllers.clear(); 826 int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); 827 for (int i = start /* get out of normal index range */; i < start + num; i++) { 828 subs.add(addSignalController(i, i)); 829 } 830 mCallbackHandler.setSubs(subs); 831 } 832 } 833 String nosim = args.getString("nosim"); 834 if (nosim != null) { 835 mHasNoSims = nosim.equals("show"); 836 mCallbackHandler.setNoSims(mHasNoSims); 837 } 838 String mobile = args.getString("mobile"); 839 if (mobile != null) { 840 boolean show = mobile.equals("show"); 841 String datatype = args.getString("datatype"); 842 String slotString = args.getString("slot"); 843 int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString); 844 slot = MathUtils.constrain(slot, 0, 8); 845 // Ensure we have enough sim slots 846 List<SubscriptionInfo> subs = new ArrayList<>(); 847 while (mMobileSignalControllers.size() <= slot) { 848 int nextSlot = mMobileSignalControllers.size(); 849 subs.add(addSignalController(nextSlot, nextSlot)); 850 } 851 if (!subs.isEmpty()) { 852 mCallbackHandler.setSubs(subs); 853 } 854 // Hack to index linearly for easy use. 855 MobileSignalController controller = mMobileSignalControllers.valueAt(slot); 856 controller.getState().dataSim = datatype != null; 857 controller.getState().isDefault = datatype != null; 858 controller.getState().dataConnected = datatype != null; 859 if (datatype != null) { 860 controller.getState().iconGroup = 861 datatype.equals("1x") ? TelephonyIcons.ONE_X : 862 datatype.equals("3g") ? TelephonyIcons.THREE_G : 863 datatype.equals("4g") ? TelephonyIcons.FOUR_G : 864 datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS : 865 datatype.equals("e") ? TelephonyIcons.E : 866 datatype.equals("g") ? TelephonyIcons.G : 867 datatype.equals("h") ? TelephonyIcons.H : 868 datatype.equals("lte") ? TelephonyIcons.LTE : 869 datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS : 870 datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED : 871 TelephonyIcons.UNKNOWN; 872 } 873 if (args.containsKey("roam")) { 874 controller.getState().roaming = "show".equals(args.getString("roam")); 875 } 876 String level = args.getString("level"); 877 if (level != null) { 878 controller.getState().level = level.equals("null") ? -1 879 : Math.min(Integer.parseInt(level), 880 SignalStrength.NUM_SIGNAL_STRENGTH_BINS); 881 controller.getState().connected = controller.getState().level >= 0; 882 } 883 String activity = args.getString("activity"); 884 if (activity != null) { 885 controller.getState().dataConnected = true; 886 switch (activity) { 887 case "inout": 888 controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT); 889 break; 890 case "in": 891 controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN); 892 break; 893 case "out": 894 controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT); 895 break; 896 default: 897 controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE); 898 break; 899 } 900 } else { 901 controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE); 902 } 903 controller.getState().enabled = show; 904 controller.notifyListeners(); 905 } 906 String carrierNetworkChange = args.getString("carriernetworkchange"); 907 if (carrierNetworkChange != null) { 908 boolean show = carrierNetworkChange.equals("show"); 909 for (int i = 0; i < mMobileSignalControllers.size(); i++) { 910 MobileSignalController controller = mMobileSignalControllers.valueAt(i); 911 controller.setCarrierNetworkChangeMode(show); 912 } 913 } 914 } 915 } 916 917 private SubscriptionInfo addSignalController(int id, int simSlotIndex) { 918 SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0, 919 null, 0, 0, ""); 920 MobileSignalController controller = new MobileSignalController(mContext, 921 mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info, 922 mSubDefaults, mReceiverHandler.getLooper()); 923 mMobileSignalControllers.put(id, controller); 924 controller.getState().userSetup = true; 925 return info; 926 } 927 928 public boolean hasEmergencyCryptKeeperText() { 929 return EncryptionHelper.IS_DATA_ENCRYPTED; 930 } 931 932 public boolean isRadioOn() { 933 return !mAirplaneMode; 934 } 935 936 private class SubListener extends OnSubscriptionsChangedListener { 937 @Override 938 public void onSubscriptionsChanged() { 939 updateMobileControllers(); 940 } 941 } 942 943 /** 944 * Used to register listeners from the BG Looper, this way the PhoneStateListeners that 945 * get created will also run on the BG Looper. 946 */ 947 private final Runnable mRegisterListeners = new Runnable() { 948 @Override 949 public void run() { 950 registerListeners(); 951 } 952 }; 953 954 public static class SubscriptionDefaults { 955 public int getDefaultVoiceSubId() { 956 return SubscriptionManager.getDefaultVoiceSubscriptionId(); 957 } 958 959 public int getDefaultDataSubId() { 960 return SubscriptionManager.getDefaultDataSubscriptionId(); 961 } 962 } 963 964 @VisibleForTesting 965 static class Config { 966 boolean showAtLeast3G = false; 967 boolean alwaysShowCdmaRssi = false; 968 boolean show4gForLte = false; 969 boolean hideLtePlus = false; 970 boolean hspaDataDistinguishable; 971 972 static Config readConfig(Context context) { 973 Config config = new Config(); 974 Resources res = context.getResources(); 975 976 config.showAtLeast3G = res.getBoolean(R.bool.config_showMin3G); 977 config.alwaysShowCdmaRssi = 978 res.getBoolean(com.android.internal.R.bool.config_alwaysUseCdmaRssi); 979 config.show4gForLte = res.getBoolean(R.bool.config_show4GForLTE); 980 config.hspaDataDistinguishable = 981 res.getBoolean(R.bool.config_hspa_data_distinguishable); 982 config.hideLtePlus = res.getBoolean(R.bool.config_hideLtePlus); 983 return config; 984 } 985 } 986 } 987