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