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