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