2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.systemui.statusbar.policy;
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;
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;
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;
59 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
61 /** Platform implementation of the network controller. **/
62 public class NetworkControllerImpl extends BroadcastReceiver
63 implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider {
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);
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;
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;
87 final WifiSignalController mWifiSignalController;
90 final EthernetSignalController mEthernetSignalController;
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;
101 private boolean mInetCondition; // Used for Logging and demo.
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();
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<>();
118 // The current user ID.
119 private int mCurrentUserId;
121 private OnSubscriptionsChangedListener mSubscriptionListener;
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;
128 private int mEmergencySource;
129 private boolean mIsEmergency;
132 ServiceState mLastServiceState;
133 private boolean mUserSetup;
136 * Construct this controller object and register for updates.
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);
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) {
160 mReceiverHandler = new Handler(bgLooper);
161 mCallbackHandler = callbackHandler;
162 mDataSaverController = new DataSaverController(context);
164 mSubscriptionManager = subManager;
165 mSubDefaults = defaultsHandler;
166 mConnectivityManager = connectivityManager;
167 mHasMobileDataFeature =
168 mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
171 mPhone = telephonyManager;
174 mWifiManager = wifiManager;
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() {
183 public void onMobileDataEnabled(boolean enabled) {
184 mCallbackHandler.setMobileDataEnabled(enabled);
187 mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
188 mCallbackHandler, this);
190 mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this);
192 // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
193 updateAirplaneMode(true /* force callback */);
196 public DataSaverController getDataSaverController() {
197 return mDataSaverController;
200 private void registerListeners() {
201 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
202 mobileSignalController.registerListener();
204 if (mSubscriptionListener == null) {
205 mSubscriptionListener = new SubListener();
207 mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
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);
225 updateMobileControllers();
228 private void unregisterListeners() {
230 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
231 mobileSignalController.unregisterListener();
233 mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener);
234 mContext.unregisterReceiver(this);
237 public int getConnectedWifiLevel() {
238 return mWifiSignalController.getState().level;
242 public AccessPointController getAccessPointController() {
243 return mAccessPoints;
247 public DataUsageController getMobileDataController() {
248 return mDataUsageController;
251 public void addEmergencyListener(EmergencyListener listener) {
252 mCallbackHandler.setListening(listener, true);
253 mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
256 public void removeEmergencyListener(EmergencyListener listener) {
257 mCallbackHandler.setListening(listener, false);
260 public boolean hasMobileDataFeature() {
261 return mHasMobileDataFeature;
264 public boolean hasVoiceCallingFeature() {
265 return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
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;
274 if (mMobileSignalControllers.containsKey(dataSubId)) {
275 return mMobileSignalControllers.get(dataSubId);
277 if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + dataSubId);
278 return mDefaultSignalController;
281 public String getMobileDataNetworkName() {
282 MobileSignalController controller = getDataController();
283 return controller != null ? controller.getState().networkNameData : "";
286 public boolean isEmergencyOnly() {
287 if (mMobileSignalControllers.size() == 0) {
288 // When there are no active subscriptions, determine emengency state from last
290 mEmergencySource = EMERGENCY_NO_CONTROLLERS;
291 return mLastServiceState != null && mLastServiceState.isEmergencyOnly();
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);
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;
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...
317 * Emergency status may have changed (triggered by MobileSignalController),
318 * so we should recheck and send out the state to listeners.
320 void recalculateEmergency() {
321 mIsEmergency = isEmergencyOnly();
322 mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
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);
335 mCallbackHandler.setListening(cb, true);
339 public void removeSignalCallback(SignalCallback cb) {
340 mCallbackHandler.setListening(cb, false);
344 public void setWifiEnabled(final boolean enabled) {
345 new AsyncTask<Void, Void, Void>() {
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);
355 mWifiManager.setWifiEnabled(enabled);
362 public void onUserSwitched(int newUserId) {
363 mCurrentUserId = newUserId;
364 mAccessPoints.onUserSwitched(newUserId);
365 updateConnectivity();
369 public void onReceive(Context context, Intent intent) {
371 Log.d(TAG, "onReceive: intent=" + intent);
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)) {
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
386 for (MobileSignalController controller : mMobileSignalControllers.values()) {
387 controller.handleBroadcast(intent);
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
397 recalculateEmergency();
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);
406 // Can't find this subscription... We must be out of date.
407 updateMobileControllers();
410 // No sub id, must be for the wifi.
411 mWifiSignalController.handleBroadcast(intent);
416 public void onConfigurationChanged() {
417 mConfig = Config.readConfig(mContext);
418 mReceiverHandler.post(new Runnable() {
421 handleConfigurationChanged();
427 void handleConfigurationChanged() {
428 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
429 mobileSignalController.setConfiguration(mConfig);
434 private void updateMobileControllers() {
438 doUpdateMobileControllers();
442 void doUpdateMobileControllers() {
443 List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList();
444 if (subscriptions == null) {
445 subscriptions = Collections.emptyList();
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.
455 setCurrentSubscriptions(subscriptions);
457 recalculateEmergency();
461 protected void updateNoSims() {
462 boolean hasNoSims = mHasMobileDataFeature && mMobileSignalControllers.size() == 0;
463 if (hasNoSims != mHasNoSims) {
464 mHasNoSims = hasNoSims;
465 mCallbackHandler.setNoSims(mHasNoSims);
470 void setCurrentSubscriptions(List<SubscriptionInfo> subscriptions) {
471 Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() {
473 public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) {
474 return lhs.getSimSlotIndex() == rhs.getSimSlotIndex()
475 ? lhs.getSubscriptionId() - rhs.getSubscriptionId()
476 : lhs.getSimSlotIndex() - rhs.getSimSlotIndex();
479 mCurrentSubscriptions = subscriptions;
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));
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;
500 controller.registerListener();
505 for (Integer key : cachedControllers.keySet()) {
506 if (cachedControllers.get(key) == mDefaultSignalController) {
507 mDefaultSignalController = null;
509 cachedControllers.get(key).unregisterListener();
512 mCallbackHandler.setSubs(subscriptions);
513 notifyAllListeners();
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 */);
521 public void setUserSetupComplete(final boolean userSetup) {
522 mReceiverHandler.post(new Runnable() {
525 handleSetUserSetupComplete(userSetup);
531 void handleSetUserSetupComplete(boolean userSetup) {
532 mUserSetup = userSetup;
533 for (MobileSignalController controller : mMobileSignalControllers.values()) {
534 controller.setUserSetupComplete(mUserSetup);
539 boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) {
540 if (allSubscriptions.size() != mMobileSignalControllers.size()) {
543 for (SubscriptionInfo info : allSubscriptions) {
544 if (!mMobileSignalControllers.containsKey(info.getSubscriptionId())) {
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);
563 private void refreshLocale() {
564 Locale current = mContext.getResources().getConfiguration().locale;
565 if (!current.equals(mLocale)) {
567 notifyAllListeners();
572 * Forces update of all callbacks on both SignalClusters and
573 * NetworkSignalChangedCallbacks.
575 private void notifyAllListeners() {
577 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
578 mobileSignalController.notifyListeners();
580 mWifiSignalController.notifyListeners();
581 mEthernetSignalController.notifyListeners();
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.
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);
596 * Update the Inet conditions and what network we are connected to.
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);
612 Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports);
613 Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
616 mInetCondition = !mValidatedTransports.isEmpty();
618 pushConnectivityToSignals();
622 * Pushes the current connectivity state to all SignalControllers.
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);
629 mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
630 mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
633 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
634 pw.println("NetworkController state:");
636 pw.println(" - telephony ------");
637 pw.print(" hasVoiceCallingFeature()=");
638 pw.println(hasVoiceCallingFeature());
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=");
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));
658 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
659 mobileSignalController.dump(pw);
661 mWifiSignalController.dump(pw);
663 mEthernetSignalController.dump(pw);
665 mAccessPoints.dump(pw);
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";
678 return "UNKNOWN_SOURCE";
681 private boolean mDemoMode;
682 private boolean mDemoInetCondition;
683 private WifiSignalController.WifiState mDemoWifiState;
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();
691 mDemoInetCondition = mInetCondition;
692 mDemoWifiState = mWifiSignalController.getState();
693 } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
694 if (DEBUG) Log.d(TAG, "Exiting demo mode");
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();
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,
713 String fully = args.getString("fully");
715 mDemoInetCondition = Boolean.parseBoolean(fully);
716 BitSet connected = new BitSet();
718 if (mDemoInetCondition) {
719 connected.set(mWifiSignalController.mTransportType);
721 mWifiSignalController.updateConnectivity(connected, connected);
722 for (MobileSignalController controller : mMobileSignalControllers.values()) {
723 if (mDemoInetCondition) {
724 connected.set(controller.mTransportType);
726 controller.updateConnectivity(connected, connected);
729 String wifi = args.getString("wifi");
731 boolean show = wifi.equals("show");
732 String level = args.getString("level");
734 mDemoWifiState.level = level.equals("null") ? -1
735 : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
736 mDemoWifiState.connected = mDemoWifiState.level >= 0;
738 mDemoWifiState.enabled = show;
739 mWifiSignalController.notifyListeners();
741 String sims = args.getString("sims");
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));
751 mCallbackHandler.setSubs(subs);
754 String nosim = args.getString("nosim");
756 mHasNoSims = nosim.equals("show");
757 mCallbackHandler.setNoSims(mHasNoSims);
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));
772 if (!subs.isEmpty()) {
773 mCallbackHandler.setSubs(subs);
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;
793 int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
794 String level = args.getString("level");
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;
800 controller.getState().enabled = show;
801 controller.notifyListeners();
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);
813 private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
814 SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
816 mMobileSignalControllers.put(id, new MobileSignalController(mContext,
817 mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info,
818 mSubDefaults, mReceiverHandler.getLooper()));
822 private class SubListener extends OnSubscriptionsChangedListener {
824 public void onSubscriptionsChanged() {
825 updateMobileControllers();
830 * Used to register listeners from the BG Looper, this way the PhoneStateListeners that
831 * get created will also run on the BG Looper.
833 private final Runnable mRegisterListeners = new Runnable() {
840 public static class SubscriptionDefaults {
841 public int getDefaultVoiceSubId() {
842 return SubscriptionManager.getDefaultVoiceSubscriptionId();
845 public int getDefaultDataSubId() {
846 return SubscriptionManager.getDefaultDataSubscriptionId();
851 static class Config {
852 boolean showAtLeast3G = false;
853 boolean alwaysShowCdmaRssi = false;
854 boolean show4gForLte = false;
855 boolean hideLtePlus = false;
856 boolean hspaDataDistinguishable;
858 static Config readConfig(Context context) {
859 Config config = new Config();
860 Resources res = context.getResources();
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);