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