OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / systemui / statusbar / policy / NetworkControllerImpl.java
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      */
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
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
196     public DataSaverController getDataSaverController() {
197         return mDataSaverController;
198     }
199
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
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
237     public int getConnectedWifiLevel() {
238         return mWifiSignalController.getState().level;
239     }
240
241     @Override
242     public AccessPointController getAccessPointController() {
243         return mAccessPoints;
244     }
245
246     @Override
247     public DataUsageController getMobileDataController() {
248         return mDataUsageController;
249     }
250
251     public void addEmergencyListener(EmergencyListener listener) {
252         mCallbackHandler.setListening(listener, true);
253         mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
254     }
255
256     public void removeEmergencyListener(EmergencyListener listener) {
257         mCallbackHandler.setListening(listener, false);
258     }
259
260     public boolean hasMobileDataFeature() {
261         return mHasMobileDataFeature;
262     }
263
264     public boolean hasVoiceCallingFeature() {
265         return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
266     }
267
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
281     public String getMobileDataNetworkName() {
282         MobileSignalController controller = getDataController();
283         return controller != null ? controller.getState().networkNameData : "";
284     }
285
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      */
320     void recalculateEmergency() {
321         mIsEmergency = isEmergencyOnly();
322         mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
323     }
324
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
339     public void removeSignalCallback(SignalCallback cb) {
340         mCallbackHandler.setListening(cb, false);
341     }
342
343     @Override
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
362     public void onUserSwitched(int newUserId) {
363         mCurrentUserId = newUserId;
364         mAccessPoints.onUserSwitched(newUserId);
365         updateConnectivity();
366     }
367
368     @Override
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
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
427     void handleConfigurationChanged() {
428         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
429             mobileSignalController.setConfiguration(mConfig);
430         }
431         refreshLocale();
432     }
433
434     private void updateMobileControllers() {
435         if (!mListening) {
436             return;
437         }
438         doUpdateMobileControllers();
439     }
440
441     @VisibleForTesting
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
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
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
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
531     void handleSetUserSetupComplete(boolean userSetup) {
532         mUserSetup = userSetup;
533         for (MobileSignalController controller : mMobileSignalControllers.values()) {
534             controller.setUserSetupComplete(mUserSetup);
535         }
536     }
537
538     @VisibleForTesting
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
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
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      */
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      */
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      */
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      */
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
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
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
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
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
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 {
841         public int getDefaultVoiceSubId() {
842             return SubscriptionManager.getDefaultVoiceSubscriptionId();
843         }
844
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
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 }