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