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 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("e") ? TelephonyIcons.E :
    785                             datatype.equals("g") ? TelephonyIcons.G :
    786                             datatype.equals("h") ? TelephonyIcons.H :
    787                             datatype.equals("lte") ? TelephonyIcons.LTE :
    788                             datatype.equals("roam") ? TelephonyIcons.ROAMING :
    789                             TelephonyIcons.UNKNOWN;
    790                 }
    791                 int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
    792                 String level = args.getString("level");
    793                 if (level != null) {
    794                     controller.getState().level = level.equals("null") ? -1
    795                             : Math.min(Integer.parseInt(level), icons[0].length - 1);
    796                     controller.getState().connected = controller.getState().level >= 0;
    797                 }
    798                 controller.getState().enabled = show;
    799                 controller.notifyListeners();
    800             }
    801             String carrierNetworkChange = args.getString("carriernetworkchange");
    802             if (carrierNetworkChange != null) {
    803                 boolean show = carrierNetworkChange.equals("show");
    804                 for (MobileSignalController controller : mMobileSignalControllers.values()) {
    805                     controller.setCarrierNetworkChangeMode(show);
    806                 }
    807             }
    808         }
    809     }
    810 
    811     private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
    812         SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
    813                 null, 0, 0, "", SubscriptionManager.SIM_PROVISIONED);
    814         mMobileSignalControllers.put(id, new MobileSignalController(mContext,
    815                 mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info,
    816                 mSubDefaults, mReceiverHandler.getLooper()));
    817         return info;
    818     }
    819 
    820     private class SubListener extends OnSubscriptionsChangedListener {
    821         @Override
    822         public void onSubscriptionsChanged() {
    823             updateMobileControllers();
    824         }
    825     }
    826 
    827     /**
    828      * Used to register listeners from the BG Looper, this way the PhoneStateListeners that
    829      * get created will also run on the BG Looper.
    830      */
    831     private final Runnable mRegisterListeners = new Runnable() {
    832         @Override
    833         public void run() {
    834             registerListeners();
    835         }
    836     };
    837 
    838     public static class SubscriptionDefaults {
    839         public int getDefaultVoiceSubId() {
    840             return SubscriptionManager.getDefaultVoiceSubscriptionId();
    841         }
    842 
    843         public int getDefaultDataSubId() {
    844             return SubscriptionManager.getDefaultDataSubscriptionId();
    845         }
    846     }
    847 
    848     @VisibleForTesting
    849     static class Config {
    850         boolean showAtLeast3G = false;
    851         boolean alwaysShowCdmaRssi = false;
    852         boolean show4gForLte = false;
    853         boolean hspaDataDistinguishable;
    854 
    855         static Config readConfig(Context context) {
    856             Config config = new Config();
    857             Resources res = context.getResources();
    858 
    859             config.showAtLeast3G = res.getBoolean(R.bool.config_showMin3G);
    860             config.alwaysShowCdmaRssi =
    861                     res.getBoolean(com.android.internal.R.bool.config_alwaysUseCdmaRssi);
    862             config.show4gForLte = res.getBoolean(R.bool.config_show4GForLTE);
    863             config.hspaDataDistinguishable =
    864                     res.getBoolean(R.bool.config_hspa_data_distinguishable);
    865             return config;
    866         }
    867     }
    868 }
    869