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
17package com.android.systemui.statusbar.policy;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.content.res.Configuration;
24import android.content.res.Resources;
25import android.net.ConnectivityManager;
26import android.net.Network;
27import android.net.NetworkCapabilities;
28import android.net.wifi.WifiManager;
29import android.os.AsyncTask;
30import android.os.Bundle;
31import android.os.Handler;
32import android.os.Looper;
33import android.os.PersistableBundle;
34import android.provider.Settings;
35import android.telephony.CarrierConfigManager;
36import android.telephony.ServiceState;
37import android.telephony.SignalStrength;
38import android.telephony.SubscriptionInfo;
39import android.telephony.SubscriptionManager;
40import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
41import android.telephony.TelephonyManager;
42import android.text.TextUtils;
43import android.util.Log;
44import android.util.MathUtils;
45import android.util.SparseArray;
46
47import com.android.internal.annotations.VisibleForTesting;
48import com.android.internal.telephony.PhoneConstants;
49import com.android.internal.telephony.TelephonyIntents;
50import com.android.settingslib.net.DataUsageController;
51import com.android.systemui.ConfigurationChangedReceiver;
52import com.android.systemui.DemoMode;
53import com.android.systemui.Dumpable;
54import com.android.systemui.R;
55import com.android.systemui.settings.CurrentUserTracker;
56import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
57
58import com.android.systemui.statusbar.policy.MobileSignalController.MobileState;
59import java.io.FileDescriptor;
60import java.io.PrintWriter;
61import java.util.ArrayList;
62import java.util.BitSet;
63import java.util.Collections;
64import java.util.Comparator;
65import java.util.List;
66import java.util.Locale;
67
68import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
69
70/** Platform implementation of the network controller. **/
71public 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