• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
isMobileDataNetworkInService()448     public boolean isMobileDataNetworkInService() {
449         MobileSignalController controller = getDataController();
450         return controller != null && controller.isInService();
451     }
452 
453     @Override
getNumberSubscriptions()454     public int getNumberSubscriptions() {
455         return mMobileSignalControllers.size();
456     }
457 
isDataControllerDisabled()458     boolean isDataControllerDisabled() {
459         MobileSignalController dataController = getDataController();
460         if (dataController == null) {
461             return false;
462         }
463 
464         return dataController.isDataDisabled();
465     }
466 
notifyControllersMobileDataChanged()467     private void notifyControllersMobileDataChanged() {
468         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
469             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
470             mobileSignalController.onMobileDataChanged();
471         }
472     }
473 
isEmergencyOnly()474     public boolean isEmergencyOnly() {
475         if (mMobileSignalControllers.size() == 0) {
476             // When there are no active subscriptions, determine emengency state from last
477             // broadcast.
478             mEmergencySource = EMERGENCY_NO_CONTROLLERS;
479             return mLastServiceState != null && mLastServiceState.isEmergencyOnly();
480         }
481         int voiceSubId = mSubDefaults.getDefaultVoiceSubId();
482         if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) {
483             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
484                 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
485                 if (!mobileSignalController.getState().isEmergency) {
486                     mEmergencySource = EMERGENCY_FIRST_CONTROLLER
487                             + mobileSignalController.mSubscriptionInfo.getSubscriptionId();
488                     if (DEBUG) Log.d(TAG, "Found emergency " + mobileSignalController.mTag);
489                     return false;
490                 }
491             }
492         }
493         if (mMobileSignalControllers.indexOfKey(voiceSubId) >= 0) {
494             mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId;
495             if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId);
496             return mMobileSignalControllers.get(voiceSubId).getState().isEmergency;
497         }
498         // If we have the wrong subId but there is only one sim anyway, assume it should be the
499         // default.
500         if (mMobileSignalControllers.size() == 1) {
501             mEmergencySource = EMERGENCY_ASSUMED_VOICE_CONTROLLER
502                     + mMobileSignalControllers.keyAt(0);
503             if (DEBUG) Log.d(TAG, "Getting assumed emergency from "
504                     + mMobileSignalControllers.keyAt(0));
505             return mMobileSignalControllers.valueAt(0).getState().isEmergency;
506         }
507         if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
508         mEmergencySource = EMERGENCY_NO_SUB + voiceSubId;
509         // Something is wrong, better assume we can't make calls...
510         return true;
511     }
512 
513     /**
514      * Emergency status may have changed (triggered by MobileSignalController),
515      * so we should recheck and send out the state to listeners.
516      */
recalculateEmergency()517     void recalculateEmergency() {
518         mIsEmergency = isEmergencyOnly();
519         mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
520     }
521 
addCallback(SignalCallback cb)522     public void addCallback(SignalCallback cb) {
523         cb.setSubs(mCurrentSubscriptions);
524         cb.setIsAirplaneMode(new IconState(mAirplaneMode,
525                 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
526         cb.setNoSims(mHasNoSubs, mSimDetected);
527         mWifiSignalController.notifyListeners(cb);
528         mEthernetSignalController.notifyListeners(cb);
529         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
530             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
531             mobileSignalController.notifyListeners(cb);
532         }
533         mCallbackHandler.setListening(cb, true);
534     }
535 
536     @Override
removeCallback(SignalCallback cb)537     public void removeCallback(SignalCallback cb) {
538         mCallbackHandler.setListening(cb, false);
539     }
540 
541     @Override
setWifiEnabled(final boolean enabled)542     public void setWifiEnabled(final boolean enabled) {
543         new AsyncTask<Void, Void, Void>() {
544             @Override
545             protected Void doInBackground(Void... args) {
546                 mWifiManager.setWifiEnabled(enabled);
547                 return null;
548             }
549         }.execute();
550     }
551 
onUserSwitched(int newUserId)552     private void onUserSwitched(int newUserId) {
553         mCurrentUserId = newUserId;
554         mAccessPoints.onUserSwitched(newUserId);
555         updateConnectivity();
556     }
557 
558     @Override
onReceive(Context context, Intent intent)559     public void onReceive(Context context, Intent intent) {
560         if (CHATTY) {
561             Log.d(TAG, "onReceive: intent=" + intent);
562         }
563         final String action = intent.getAction();
564         switch (action) {
565             case ConnectivityManager.CONNECTIVITY_ACTION:
566             case ConnectivityManager.INET_CONDITION_ACTION:
567                 updateConnectivity();
568                 break;
569             case Intent.ACTION_AIRPLANE_MODE_CHANGED:
570                 refreshLocale();
571                 updateAirplaneMode(false);
572                 break;
573             case TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED:
574                 // We are using different subs now, we might be able to make calls.
575                 recalculateEmergency();
576                 break;
577             case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
578                 // Notify every MobileSignalController so they can know whether they are the
579                 // data sim or not.
580                 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
581                     MobileSignalController controller = mMobileSignalControllers.valueAt(i);
582                     controller.handleBroadcast(intent);
583                 }
584                 mConfig = Config.readConfig(mContext);
585                 mReceiverHandler.post(this::handleConfigurationChanged);
586                 break;
587             case Intent.ACTION_SIM_STATE_CHANGED:
588                 // Avoid rebroadcast because SysUI is direct boot aware.
589                 if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
590                     break;
591                 }
592                 // Might have different subscriptions now.
593                 updateMobileControllers();
594                 break;
595             case Intent.ACTION_SERVICE_STATE:
596                 mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
597                 if (mMobileSignalControllers.size() == 0) {
598                     // If none of the subscriptions are active, we might need to recalculate
599                     // emergency state.
600                     recalculateEmergency();
601                 }
602                 break;
603             case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
604                 mConfig = Config.readConfig(mContext);
605                 mReceiverHandler.post(this::handleConfigurationChanged);
606                 break;
607             default:
608                 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
609                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
610                 if (SubscriptionManager.isValidSubscriptionId(subId)) {
611                     if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
612                         mMobileSignalControllers.get(subId).handleBroadcast(intent);
613                     } else {
614                         // Can't find this subscription...  We must be out of date.
615                         updateMobileControllers();
616                     }
617                 } else {
618                     // No sub id, must be for the wifi.
619                     mWifiSignalController.handleBroadcast(intent);
620                 }
621                 break;
622         }
623     }
624 
625     @VisibleForTesting
handleConfigurationChanged()626     void handleConfigurationChanged() {
627         updateMobileControllers();
628         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
629             MobileSignalController controller = mMobileSignalControllers.valueAt(i);
630             controller.setConfiguration(mConfig);
631         }
632         refreshLocale();
633     }
634 
updateMobileControllers()635     private void updateMobileControllers() {
636         if (!mListening) {
637             return;
638         }
639         doUpdateMobileControllers();
640     }
641 
filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions)642     private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
643         if (subscriptions.size() == 2) {
644             SubscriptionInfo info1 = subscriptions.get(0);
645             SubscriptionInfo info2 = subscriptions.get(1);
646             if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
647                 // If both subscriptions are primary, show both.
648                 if (!info1.isOpportunistic() && !info2.isOpportunistic()) return;
649 
650                 // If carrier required, always show signal bar of primary subscription.
651                 // Otherwise, show whichever subscription is currently active for Internet.
652                 boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig()
653                         .getBoolean(CarrierConfigManager
654                         .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN);
655                 if (alwaysShowPrimary) {
656                     subscriptions.remove(info1.isOpportunistic() ? info1 : info2);
657                 } else {
658                     subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription
659                             ? info2 : info1);
660                 }
661             }
662         }
663     }
664 
665     @VisibleForTesting
doUpdateMobileControllers()666     void doUpdateMobileControllers() {
667         List<SubscriptionInfo> subscriptions = mSubscriptionManager
668                 .getCompleteActiveSubscriptionInfoList();
669         if (subscriptions == null) {
670             subscriptions = Collections.emptyList();
671         }
672 
673         filterMobileSubscriptionInSameGroup(subscriptions);
674 
675         // If there have been no relevant changes to any of the subscriptions, we can leave as is.
676         if (hasCorrectMobileControllers(subscriptions)) {
677             // Even if the controllers are correct, make sure we have the right no sims state.
678             // Such as on boot, don't need any controllers, because there are no sims,
679             // but we still need to update the no sim state.
680             updateNoSims();
681             return;
682         }
683         synchronized (mLock) {
684             setCurrentSubscriptionsLocked(subscriptions);
685         }
686         updateNoSims();
687         recalculateEmergency();
688     }
689 
690     @VisibleForTesting
updateNoSims()691     protected void updateNoSims() {
692         boolean hasNoSubs = mHasMobileDataFeature && mMobileSignalControllers.size() == 0;
693         boolean simDetected = hasAnySim();
694         if (hasNoSubs != mHasNoSubs || simDetected != mSimDetected) {
695             mHasNoSubs = hasNoSubs;
696             mSimDetected = simDetected;
697             mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
698         }
699     }
700 
hasAnySim()701     private boolean hasAnySim() {
702         int simCount = mPhone.getActiveModemCount();
703         for (int i = 0; i < simCount; i++) {
704             int state = mPhone.getSimState(i);
705             if (state != TelephonyManager.SIM_STATE_ABSENT
706                     && state != TelephonyManager.SIM_STATE_UNKNOWN) {
707                 return true;
708             }
709         }
710         return false;
711     }
712 
713     @GuardedBy("mLock")
714     @VisibleForTesting
setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions)715     public void setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions) {
716         Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() {
717             @Override
718             public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) {
719                 return lhs.getSimSlotIndex() == rhs.getSimSlotIndex()
720                         ? lhs.getSubscriptionId() - rhs.getSubscriptionId()
721                         : lhs.getSimSlotIndex() - rhs.getSimSlotIndex();
722             }
723         });
724         mCurrentSubscriptions = subscriptions;
725 
726         SparseArray<MobileSignalController> cachedControllers =
727                 new SparseArray<MobileSignalController>();
728         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
729             cachedControllers.put(mMobileSignalControllers.keyAt(i),
730                     mMobileSignalControllers.valueAt(i));
731         }
732         mMobileSignalControllers.clear();
733         final int num = subscriptions.size();
734         for (int i = 0; i < num; i++) {
735             int subId = subscriptions.get(i).getSubscriptionId();
736             // If we have a copy of this controller already reuse it, otherwise make a new one.
737             if (cachedControllers.indexOfKey(subId) >= 0) {
738                 mMobileSignalControllers.put(subId, cachedControllers.get(subId));
739                 cachedControllers.remove(subId);
740             } else {
741                 MobileSignalController controller = new MobileSignalController(mContext, mConfig,
742                         mHasMobileDataFeature, mPhone.createForSubscriptionId(subId),
743                         mCallbackHandler, this, subscriptions.get(i),
744                         mSubDefaults, mReceiverHandler.getLooper());
745                 controller.setUserSetupComplete(mUserSetup);
746                 mMobileSignalControllers.put(subId, controller);
747                 if (subscriptions.get(i).getSimSlotIndex() == 0) {
748                     mDefaultSignalController = controller;
749                 }
750                 if (mListening) {
751                     controller.registerListener();
752                 }
753             }
754         }
755         if (mListening) {
756             for (int i = 0; i < cachedControllers.size(); i++) {
757                 int key = cachedControllers.keyAt(i);
758                 if (cachedControllers.get(key) == mDefaultSignalController) {
759                     mDefaultSignalController = null;
760                 }
761                 cachedControllers.get(key).unregisterListener();
762             }
763         }
764         mCallbackHandler.setSubs(subscriptions);
765         notifyAllListeners();
766 
767         // There may be new MobileSignalControllers around, make sure they get the current
768         // inet condition and airplane mode.
769         pushConnectivityToSignals();
770         updateAirplaneMode(true /* force */);
771     }
772 
setUserSetupComplete(final boolean userSetup)773     private void setUserSetupComplete(final boolean userSetup) {
774         mReceiverHandler.post(() -> handleSetUserSetupComplete(userSetup));
775     }
776 
handleSetUserSetupComplete(boolean userSetup)777     private void handleSetUserSetupComplete(boolean userSetup) {
778         mUserSetup = userSetup;
779         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
780             MobileSignalController controller = mMobileSignalControllers.valueAt(i);
781             controller.setUserSetupComplete(mUserSetup);
782         }
783     }
784 
785     @VisibleForTesting
hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions)786     boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) {
787         if (allSubscriptions.size() != mMobileSignalControllers.size()) {
788             return false;
789         }
790         for (SubscriptionInfo info : allSubscriptions) {
791             if (mMobileSignalControllers.indexOfKey(info.getSubscriptionId()) < 0) {
792                 return false;
793             }
794         }
795         return true;
796     }
797 
updateAirplaneMode(boolean force)798     private void updateAirplaneMode(boolean force) {
799         boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
800                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
801         if (airplaneMode != mAirplaneMode || force) {
802             mAirplaneMode = airplaneMode;
803             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
804                 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
805                 mobileSignalController.setAirplaneMode(mAirplaneMode);
806             }
807             notifyListeners();
808         }
809     }
810 
refreshLocale()811     private void refreshLocale() {
812         Locale current = mContext.getResources().getConfiguration().locale;
813         if (!current.equals(mLocale)) {
814             mLocale = current;
815             mWifiSignalController.refreshLocale();
816             notifyAllListeners();
817         }
818     }
819 
820     /**
821      * Forces update of all callbacks on both SignalClusters and
822      * NetworkSignalChangedCallbacks.
823      */
notifyAllListeners()824     private void notifyAllListeners() {
825         notifyListeners();
826         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
827             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
828             mobileSignalController.notifyListeners();
829         }
830         mWifiSignalController.notifyListeners();
831         mEthernetSignalController.notifyListeners();
832     }
833 
834     /**
835      * Notifies listeners of changes in state of to the NetworkController, but
836      * does not notify for any info on SignalControllers, for that call
837      * notifyAllListeners.
838      */
notifyListeners()839     private void notifyListeners() {
840         mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
841                 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
842         mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
843     }
844 
845     /**
846      * Update the Inet conditions and what network we are connected to.
847      */
updateConnectivity()848     private void updateConnectivity() {
849         mConnectedTransports.clear();
850         mValidatedTransports.clear();
851         for (NetworkCapabilities nc :
852                 mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) {
853             for (int transportType : nc.getTransportTypes()) {
854                 mConnectedTransports.set(transportType);
855                 if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) {
856                     mValidatedTransports.set(transportType);
857                 }
858             }
859         }
860 
861         if (mForceCellularValidated) mValidatedTransports.set(TRANSPORT_CELLULAR);
862 
863         if (CHATTY) {
864             Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports);
865             Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
866         }
867 
868         mInetCondition = !mValidatedTransports.isEmpty();
869 
870         pushConnectivityToSignals();
871     }
872 
873     /**
874      * Pushes the current connectivity state to all SignalControllers.
875      */
pushConnectivityToSignals()876     private void pushConnectivityToSignals() {
877         // We want to update all the icons, all at once, for any condition change
878         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
879             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
880             mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
881         }
882         mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
883         mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
884     }
885 
dump(FileDescriptor fd, PrintWriter pw, String[] args)886     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
887         pw.println("NetworkController state:");
888 
889         pw.println("  - telephony ------");
890         pw.print("  hasVoiceCallingFeature()=");
891         pw.println(hasVoiceCallingFeature());
892         pw.println("  mListening=" + mListening);
893 
894         pw.println("  - connectivity ------");
895         pw.print("  mConnectedTransports=");
896         pw.println(mConnectedTransports);
897         pw.print("  mValidatedTransports=");
898         pw.println(mValidatedTransports);
899         pw.print("  mInetCondition=");
900         pw.println(mInetCondition);
901         pw.print("  mAirplaneMode=");
902         pw.println(mAirplaneMode);
903         pw.print("  mLocale=");
904         pw.println(mLocale);
905         pw.print("  mLastServiceState=");
906         pw.println(mLastServiceState);
907         pw.print("  mIsEmergency=");
908         pw.println(mIsEmergency);
909         pw.print("  mEmergencySource=");
910         pw.println(emergencyToString(mEmergencySource));
911 
912         pw.println("  - config ------");
913         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
914             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
915             mobileSignalController.dump(pw);
916         }
917         mWifiSignalController.dump(pw);
918 
919         mEthernetSignalController.dump(pw);
920 
921         mAccessPoints.dump(pw);
922     }
923 
emergencyToString(int emergencySource)924     private static final String emergencyToString(int emergencySource) {
925         if (emergencySource > EMERGENCY_NO_SUB) {
926             return "ASSUMED_VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER)
927                     + ")";
928         } else if (emergencySource > EMERGENCY_NO_SUB) {
929             return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")";
930         } else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) {
931             return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")";
932         } else if (emergencySource > EMERGENCY_FIRST_CONTROLLER) {
933             return "FIRST_CONTROLLER(" + (emergencySource - EMERGENCY_FIRST_CONTROLLER) + ")";
934         } else if (emergencySource == EMERGENCY_NO_CONTROLLERS) {
935             return "NO_CONTROLLERS";
936         }
937         return "UNKNOWN_SOURCE";
938     }
939 
940     private boolean mDemoMode;
941     private boolean mDemoInetCondition;
942     private WifiSignalController.WifiState mDemoWifiState;
943 
944     @Override
dispatchDemoCommand(String command, Bundle args)945     public void dispatchDemoCommand(String command, Bundle args) {
946         if (!mDemoMode && command.equals(COMMAND_ENTER)) {
947             if (DEBUG) Log.d(TAG, "Entering demo mode");
948             unregisterListeners();
949             mDemoMode = true;
950             mDemoInetCondition = mInetCondition;
951             mDemoWifiState = mWifiSignalController.getState();
952             mDemoWifiState.ssid = "DemoMode";
953         } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
954             if (DEBUG) Log.d(TAG, "Exiting demo mode");
955             mDemoMode = false;
956             // Update what MobileSignalControllers, because they may change
957             // to set the number of sim slots.
958             updateMobileControllers();
959             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
960                 MobileSignalController controller = mMobileSignalControllers.valueAt(i);
961                 controller.resetLastState();
962             }
963             mWifiSignalController.resetLastState();
964             mReceiverHandler.post(mRegisterListeners);
965             notifyAllListeners();
966         } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
967             String airplane = args.getString("airplane");
968             if (airplane != null) {
969                 boolean show = airplane.equals("show");
970                 mCallbackHandler.setIsAirplaneMode(new IconState(show,
971                         TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode,
972                         mContext));
973             }
974             String fully = args.getString("fully");
975             if (fully != null) {
976                 mDemoInetCondition = Boolean.parseBoolean(fully);
977                 BitSet connected = new BitSet();
978 
979                 if (mDemoInetCondition) {
980                     connected.set(mWifiSignalController.mTransportType);
981                 }
982                 mWifiSignalController.updateConnectivity(connected, connected);
983                 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
984                     MobileSignalController controller = mMobileSignalControllers.valueAt(i);
985                     if (mDemoInetCondition) {
986                         connected.set(controller.mTransportType);
987                     }
988                     controller.updateConnectivity(connected, connected);
989                 }
990             }
991             String wifi = args.getString("wifi");
992             if (wifi != null) {
993                 boolean show = wifi.equals("show");
994                 String level = args.getString("level");
995                 if (level != null) {
996                     mDemoWifiState.level = level.equals("null") ? -1
997                             : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
998                     mDemoWifiState.connected = mDemoWifiState.level >= 0;
999                 }
1000                 String activity = args.getString("activity");
1001                 if (activity != null) {
1002                     switch (activity) {
1003                         case "inout":
1004                             mWifiSignalController.setActivity(DATA_ACTIVITY_INOUT);
1005                             break;
1006                         case "in":
1007                             mWifiSignalController.setActivity(DATA_ACTIVITY_IN);
1008                             break;
1009                         case "out":
1010                             mWifiSignalController.setActivity(DATA_ACTIVITY_OUT);
1011                             break;
1012                         default:
1013                             mWifiSignalController.setActivity(DATA_ACTIVITY_NONE);
1014                             break;
1015                     }
1016                 } else {
1017                     mWifiSignalController.setActivity(DATA_ACTIVITY_NONE);
1018                 }
1019                 String ssid = args.getString("ssid");
1020                 if (ssid != null) {
1021                     mDemoWifiState.ssid = ssid;
1022                 }
1023                 mDemoWifiState.enabled = show;
1024                 mWifiSignalController.notifyListeners();
1025             }
1026             String sims = args.getString("sims");
1027             if (sims != null) {
1028                 int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8);
1029                 List<SubscriptionInfo> subs = new ArrayList<>();
1030                 if (num != mMobileSignalControllers.size()) {
1031                     mMobileSignalControllers.clear();
1032                     int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
1033                     for (int i = start /* get out of normal index range */; i < start + num; i++) {
1034                         subs.add(addSignalController(i, i));
1035                     }
1036                     mCallbackHandler.setSubs(subs);
1037                     for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1038                         int key = mMobileSignalControllers.keyAt(i);
1039                         MobileSignalController controller = mMobileSignalControllers.get(key);
1040                         controller.notifyListeners();
1041                     }
1042                 }
1043             }
1044             String nosim = args.getString("nosim");
1045             if (nosim != null) {
1046                 mHasNoSubs = nosim.equals("show");
1047                 mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
1048             }
1049             String mobile = args.getString("mobile");
1050             if (mobile != null) {
1051                 boolean show = mobile.equals("show");
1052                 String datatype = args.getString("datatype");
1053                 String slotString = args.getString("slot");
1054                 int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString);
1055                 slot = MathUtils.constrain(slot, 0, 8);
1056                 // Ensure we have enough sim slots
1057                 List<SubscriptionInfo> subs = new ArrayList<>();
1058                 while (mMobileSignalControllers.size() <= slot) {
1059                     int nextSlot = mMobileSignalControllers.size();
1060                     subs.add(addSignalController(nextSlot, nextSlot));
1061                 }
1062                 if (!subs.isEmpty()) {
1063                     mCallbackHandler.setSubs(subs);
1064                 }
1065                 // Hack to index linearly for easy use.
1066                 MobileSignalController controller = mMobileSignalControllers.valueAt(slot);
1067                 controller.getState().dataSim = datatype != null;
1068                 controller.getState().isDefault = datatype != null;
1069                 controller.getState().dataConnected = datatype != null;
1070                 if (datatype != null) {
1071                     controller.getState().iconGroup =
1072                             datatype.equals("1x") ? TelephonyIcons.ONE_X :
1073                             datatype.equals("3g") ? TelephonyIcons.THREE_G :
1074                             datatype.equals("4g") ? TelephonyIcons.FOUR_G :
1075                             datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS :
1076                             datatype.equals("5g") ? TelephonyIcons.NR_5G :
1077                             datatype.equals("5ge") ? TelephonyIcons.LTE_CA_5G_E :
1078                             datatype.equals("5g+") ? TelephonyIcons.NR_5G_PLUS :
1079                             datatype.equals("e") ? TelephonyIcons.E :
1080                             datatype.equals("g") ? TelephonyIcons.G :
1081                             datatype.equals("h") ? TelephonyIcons.H :
1082                             datatype.equals("h+") ? TelephonyIcons.H_PLUS :
1083                             datatype.equals("lte") ? TelephonyIcons.LTE :
1084                             datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS :
1085                             datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED :
1086                             datatype.equals("not") ? TelephonyIcons.NOT_DEFAULT_DATA :
1087                             TelephonyIcons.UNKNOWN;
1088                 }
1089                 if (args.containsKey("roam")) {
1090                     controller.getState().roaming = "show".equals(args.getString("roam"));
1091                 }
1092                 String level = args.getString("level");
1093                 if (level != null) {
1094                     controller.getState().level = level.equals("null") ? -1
1095                             : Math.min(Integer.parseInt(level),
1096                                     CellSignalStrength.getNumSignalStrengthLevels());
1097                     controller.getState().connected = controller.getState().level >= 0;
1098                 }
1099                 if (args.containsKey("inflate")) {
1100                     for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1101                         mMobileSignalControllers.valueAt(i).mInflateSignalStrengths =
1102                                 "true".equals(args.getString("inflate"));
1103                     }
1104                 }
1105                 String activity = args.getString("activity");
1106                 if (activity != null) {
1107                     controller.getState().dataConnected = true;
1108                     switch (activity) {
1109                         case "inout":
1110                             controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
1111                             break;
1112                         case "in":
1113                             controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN);
1114                             break;
1115                         case "out":
1116                             controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT);
1117                             break;
1118                         default:
1119                             controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
1120                             break;
1121                     }
1122                 } else {
1123                     controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
1124                 }
1125                 controller.getState().enabled = show;
1126                 controller.notifyListeners();
1127             }
1128             String carrierNetworkChange = args.getString("carriernetworkchange");
1129             if (carrierNetworkChange != null) {
1130                 boolean show = carrierNetworkChange.equals("show");
1131                 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1132                     MobileSignalController controller = mMobileSignalControllers.valueAt(i);
1133                     controller.setCarrierNetworkChangeMode(show);
1134                 }
1135             }
1136         }
1137     }
1138 
addSignalController(int id, int simSlotIndex)1139     private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
1140         SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
1141                 null, null, null, "", false, null, null);
1142         MobileSignalController controller = new MobileSignalController(mContext,
1143                 mConfig, mHasMobileDataFeature,
1144                 mPhone.createForSubscriptionId(info.getSubscriptionId()), mCallbackHandler, this, info,
1145                 mSubDefaults, mReceiverHandler.getLooper());
1146         mMobileSignalControllers.put(id, controller);
1147         controller.getState().userSetup = true;
1148         return info;
1149     }
1150 
hasEmergencyCryptKeeperText()1151     public boolean hasEmergencyCryptKeeperText() {
1152         return EncryptionHelper.IS_DATA_ENCRYPTED;
1153     }
1154 
isRadioOn()1155     public boolean isRadioOn() {
1156         return !mAirplaneMode;
1157     }
1158 
1159     private class SubListener extends OnSubscriptionsChangedListener {
1160         @Override
onSubscriptionsChanged()1161         public void onSubscriptionsChanged() {
1162             updateMobileControllers();
1163         }
1164     }
1165 
1166     /**
1167      * Used to register listeners from the BG Looper, this way the PhoneStateListeners that
1168      * get created will also run on the BG Looper.
1169      */
1170     private final Runnable mRegisterListeners = new Runnable() {
1171         @Override
1172         public void run() {
1173             registerListeners();
1174         }
1175     };
1176 
1177     public static class SubscriptionDefaults {
getDefaultVoiceSubId()1178         public int getDefaultVoiceSubId() {
1179             return SubscriptionManager.getDefaultVoiceSubscriptionId();
1180         }
1181 
getDefaultDataSubId()1182         public int getDefaultDataSubId() {
1183             return SubscriptionManager.getDefaultDataSubscriptionId();
1184         }
1185 
getActiveDataSubId()1186         public int getActiveDataSubId() {
1187             return SubscriptionManager.getActiveDataSubscriptionId();
1188         }
1189     }
1190 
1191     @VisibleForTesting
1192     static class Config {
1193         boolean showAtLeast3G = false;
1194         boolean show4gFor3g = false;
1195         boolean alwaysShowCdmaRssi = false;
1196         boolean show4gForLte = false;
1197         boolean hideLtePlus = false;
1198         boolean hspaDataDistinguishable;
1199         boolean inflateSignalStrengths = false;
1200         boolean alwaysShowDataRatIcon = false;
1201 
readConfig(Context context)1202         static Config readConfig(Context context) {
1203             Config config = new Config();
1204             Resources res = context.getResources();
1205 
1206             config.showAtLeast3G = res.getBoolean(R.bool.config_showMin3G);
1207             config.alwaysShowCdmaRssi =
1208                     res.getBoolean(com.android.internal.R.bool.config_alwaysUseCdmaRssi);
1209             config.hspaDataDistinguishable =
1210                     res.getBoolean(R.bool.config_hspa_data_distinguishable);
1211             config.inflateSignalStrengths = res.getBoolean(
1212                     com.android.internal.R.bool.config_inflateSignalStrength);
1213 
1214             CarrierConfigManager configMgr = (CarrierConfigManager)
1215                     context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1216             // Handle specific carrier config values for the default data SIM
1217             int defaultDataSubId = SubscriptionManager.from(context)
1218                     .getDefaultDataSubscriptionId();
1219             PersistableBundle b = configMgr.getConfigForSubId(defaultDataSubId);
1220             if (b != null) {
1221                 config.alwaysShowDataRatIcon = b.getBoolean(
1222                         CarrierConfigManager.KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL);
1223                 config.show4gForLte = b.getBoolean(
1224                         CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
1225                 config.show4gFor3g = b.getBoolean(
1226                         CarrierConfigManager.KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL);
1227                 config.hideLtePlus = b.getBoolean(
1228                         CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL);
1229             }
1230 
1231             return config;
1232         }
1233     }
1234 }
1235