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