Home | History | Annotate | Download | only in policy
      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      */
    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
    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 
    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 
    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 
    229     public int getConnectedWifiLevel() {
    230         return mWifiSignalController.getState().level;
    231     }
    232 
    233     @Override
    234     public AccessPointController getAccessPointController() {
    235         return mAccessPoints;
    236     }
    237 
    238     @Override
    239     public MobileDataController getMobileDataController() {
    240         return mMobileDataController;
    241     }
    242 
    243     public void addEmergencyListener(EmergencyListener listener) {
    244         mCallbackHandler.setListening(listener, true);
    245         mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
    246     }
    247 
    248     public boolean hasMobileDataFeature() {
    249         return mHasMobileDataFeature;
    250     }
    251 
    252     public boolean hasVoiceCallingFeature() {
    253         return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
    254     }
    255 
    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 
    269     public String getMobileDataNetworkName() {
    270         MobileSignalController controller = getDataController();
    271         return controller != null ? controller.getState().networkNameData : "";
    272     }
    273 
    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      */
    308     void recalculateEmergency() {
    309         mIsEmergency = isEmergencyOnly();
    310         mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
    311     }
    312 
    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
    327     public void removeSignalCallback(SignalCallback cb) {
    328         mCallbackHandler.setListening(cb, false);
    329     }
    330 
    331     @Override
    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
    350     public void onUserSwitched(int newUserId) {
    351         mCurrentUserId = newUserId;
    352         mAccessPoints.onUserSwitched(newUserId);
    353         updateConnectivity();
    354     }
    355 
    356     @Override
    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 
    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
    415     void handleConfigurationChanged() {
    416         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
    417             mobileSignalController.setConfiguration(mConfig);
    418         }
    419         refreshLocale();
    420     }
    421 
    422     private void updateMobileControllers() {
    423         if (!mListening) {
    424             return;
    425         }
    426         doUpdateMobileControllers();
    427     }
    428 
    429     @VisibleForTesting
    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
    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
    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
    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 
    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 
    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      */
    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      */
    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      */
    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      */
    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 
    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 
    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
    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 
    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
    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 {
    809         void setEmergencyCallsOnly(boolean emergencyOnly);
    810     }
    811 
    812     public static class SubscriptionDefaults {
    813         public int getDefaultVoiceSubId() {
    814             return SubscriptionManager.getDefaultVoiceSubId();
    815         }
    816 
    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 
    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