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