• 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.connectivity;
18 
19 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
20 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
21 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
22 
23 import android.annotation.Nullable;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.res.Configuration;
29 import android.net.ConnectivityManager;
30 import android.net.ConnectivityManager.NetworkCallback;
31 import android.net.Network;
32 import android.net.NetworkCapabilities;
33 import android.net.wifi.ScanResult;
34 import android.net.wifi.WifiManager;
35 import android.os.AsyncTask;
36 import android.os.Bundle;
37 import android.os.Handler;
38 import android.os.HandlerExecutor;
39 import android.os.Looper;
40 import android.provider.Settings;
41 import android.telephony.CarrierConfigManager;
42 import android.telephony.CellSignalStrength;
43 import android.telephony.ServiceState;
44 import android.telephony.SubscriptionInfo;
45 import android.telephony.SubscriptionManager;
46 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
47 import android.telephony.TelephonyCallback;
48 import android.telephony.TelephonyManager;
49 import android.text.TextUtils;
50 import android.util.Log;
51 import android.util.MathUtils;
52 import android.util.SparseArray;
53 
54 import androidx.annotation.NonNull;
55 
56 import com.android.internal.annotations.GuardedBy;
57 import com.android.internal.annotations.VisibleForTesting;
58 import com.android.settingslib.Utils;
59 import com.android.settingslib.mobile.MobileMappings.Config;
60 import com.android.settingslib.mobile.MobileStatusTracker.SubscriptionDefaults;
61 import com.android.settingslib.mobile.TelephonyIcons;
62 import com.android.settingslib.net.DataUsageController;
63 import com.android.systemui.Dumpable;
64 import com.android.systemui.broadcast.BroadcastDispatcher;
65 import com.android.systemui.dagger.SysUISingleton;
66 import com.android.systemui.dagger.qualifiers.Background;
67 import com.android.systemui.dagger.qualifiers.Main;
68 import com.android.systemui.demomode.DemoMode;
69 import com.android.systemui.demomode.DemoModeController;
70 import com.android.systemui.dump.DumpManager;
71 import com.android.systemui.log.LogBuffer;
72 import com.android.systemui.log.core.LogLevel;
73 import com.android.systemui.log.dagger.StatusBarNetworkControllerLog;
74 import com.android.systemui.qs.tiles.dialog.InternetDialogManager;
75 import com.android.systemui.res.R;
76 import com.android.systemui.settings.UserTracker;
77 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
78 import com.android.systemui.statusbar.policy.ConfigurationController;
79 import com.android.systemui.statusbar.policy.DataSaverController;
80 import com.android.systemui.statusbar.policy.DataSaverControllerImpl;
81 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
82 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
83 import com.android.systemui.telephony.TelephonyListenerManager;
84 import com.android.systemui.util.CarrierConfigTracker;
85 
86 import dalvik.annotation.optimization.NeverCompile;
87 
88 import kotlin.Unit;
89 
90 import java.io.PrintWriter;
91 import java.text.SimpleDateFormat;
92 import java.util.ArrayList;
93 import java.util.Arrays;
94 import java.util.BitSet;
95 import java.util.Collections;
96 import java.util.Comparator;
97 import java.util.List;
98 import java.util.Locale;
99 import java.util.concurrent.Executor;
100 import java.util.stream.Collectors;
101 
102 import javax.inject.Inject;
103 
104 /** Platform implementation of the network controller. **/
105 @SysUISingleton
106 public class NetworkControllerImpl extends BroadcastReceiver
107         implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider, Dumpable {
108     // debug
109     static final String TAG = "NetworkController";
110     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
111     // additional diagnostics, but not logspew
112     static final boolean CHATTY =  Log.isLoggable(TAG + "Chat", Log.DEBUG);
113 
114     private static final int EMERGENCY_NO_CONTROLLERS = 0;
115     private static final int EMERGENCY_FIRST_CONTROLLER = 100;
116     private static final int EMERGENCY_VOICE_CONTROLLER = 200;
117     private static final int EMERGENCY_NO_SUB = 300;
118     private static final int EMERGENCY_ASSUMED_VOICE_CONTROLLER = 400;
119     private static final int HISTORY_SIZE = 16;
120     private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
121 
122     private final Context mContext;
123     private final TelephonyManager mPhone;
124     private final TelephonyListenerManager mTelephonyListenerManager;
125     private final WifiManager mWifiManager;
126     private final ConnectivityManager mConnectivityManager;
127     private final SubscriptionManager mSubscriptionManager;
128     private final boolean mHasMobileDataFeature;
129     private final SubscriptionDefaults mSubDefaults;
130     private final DataSaverController mDataSaverController;
131     private final UserTracker mUserTracker;
132     private final BroadcastDispatcher mBroadcastDispatcher;
133     private final DemoModeController mDemoModeController;
134     private final Object mLock = new Object();
135     private Config mConfig;
136     private final CarrierConfigTracker mCarrierConfigTracker;
137     private final DumpManager mDumpManager;
138     private final LogBuffer mLogBuffer;
139     private final MobileSignalControllerFactory mMobileFactory;
140 
141     private TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener;
142     private int mActiveMobileDataSubscription = INVALID_SUBSCRIPTION_ID;
143 
144     // Subcontrollers.
145     @VisibleForTesting
146     final WifiSignalController mWifiSignalController;
147 
148     @VisibleForTesting
149     final EthernetSignalController mEthernetSignalController;
150 
151     @VisibleForTesting
152     final SparseArray<MobileSignalController> mMobileSignalControllers = new SparseArray<>();
153     // When no SIMs are around at setup, and one is added later, it seems to default to the first
154     // SIM for most actions.  This may be null if there aren't any SIMs around.
155     private MobileSignalController mDefaultSignalController;
156     private final AccessPointControllerImpl mAccessPoints;
157     private final DataUsageController mDataUsageController;
158 
159     private boolean mInetCondition; // Used for Logging and demo.
160 
161     // BitSets indicating which network transport types (e.g., TRANSPORT_WIFI, TRANSPORT_MOBILE) are
162     // connected and validated, respectively.
163     private final BitSet mConnectedTransports = new BitSet();
164     private final BitSet mValidatedTransports = new BitSet();
165 
166     // States that don't belong to a subcontroller.
167     private boolean mAirplaneMode = false;
168     private boolean mHasNoSubs;
169     private boolean mNoDefaultNetwork = false;
170     private boolean mNoNetworksAvailable = true;
171     private Locale mLocale = null;
172     // This list holds our ordering.
173     private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>();
174 
175     // Save the previous HISTORY_SIZE states for logging.
176     private final String[] mHistory = new String[HISTORY_SIZE];
177     // Where to copy the next state into.
178     private int mHistoryIndex;
179 
180     @VisibleForTesting
181     boolean mListening;
182 
183     // The current user ID.
184     private int mCurrentUserId;
185 
186     private OnSubscriptionsChangedListener mSubscriptionListener;
187     private NetworkCapabilities mLastDefaultNetworkCapabilities;
188     // Handler that all broadcasts are received on.
189     private final Handler mReceiverHandler;
190     private final Looper mBgLooper;
191     private final Executor mBgExecutor;
192     // Handler that all callbacks are made on.
193     private final CallbackHandler mCallbackHandler;
194     private final StatusBarPipelineFlags mStatusBarPipelineFlags;
195 
196     private int mEmergencySource;
197     private boolean mIsEmergency;
198 
199     @VisibleForTesting
200     ServiceState mLastServiceState;
201     private boolean mUserSetup;
202     private boolean mSimDetected;
203     private boolean mForceCellularValidated;
204     private InternetDialogManager mInternetDialogManager;
205     private Handler mMainHandler;
206 
207     private ConfigurationController.ConfigurationListener mConfigurationListener =
208             new ConfigurationController.ConfigurationListener() {
209                 @Override
210                 public void onConfigChanged(Configuration newConfig) {
211                     mConfig = Config.readConfig(mContext);
212                     mReceiverHandler.post(() -> handleConfigurationChanged());
213                 }
214             };
215 
216     private final UserTracker.Callback mUserChangedCallback =
217             new UserTracker.Callback() {
218                 @Override
219                 public void onUserChanged(int newUser, @NonNull Context userContext) {
220                     NetworkControllerImpl.this.onUserSwitched(newUser);
221                 }
222             };
223 
224     /**
225      * Construct this controller object and register for updates.
226      */
227     @Inject
NetworkControllerImpl( Context context, @Background Looper bgLooper, @Background Executor bgExecutor, SubscriptionManager subscriptionManager, CallbackHandler callbackHandler, DeviceProvisionedController deviceProvisionedController, BroadcastDispatcher broadcastDispatcher, UserTracker userTracker, ConnectivityManager connectivityManager, TelephonyManager telephonyManager, TelephonyListenerManager telephonyListenerManager, @Nullable WifiManager wifiManager, AccessPointControllerImpl accessPointController, StatusBarPipelineFlags statusBarPipelineFlags, DemoModeController demoModeController, CarrierConfigTracker carrierConfigTracker, WifiStatusTrackerFactory trackerFactory, MobileSignalControllerFactory mobileFactory, @Main Handler handler, InternetDialogManager internetDialogManager, DumpManager dumpManager, @StatusBarNetworkControllerLog LogBuffer logBuffer)228     public NetworkControllerImpl(
229             Context context,
230             @Background Looper bgLooper,
231             @Background Executor bgExecutor,
232             SubscriptionManager subscriptionManager,
233             CallbackHandler callbackHandler,
234             DeviceProvisionedController deviceProvisionedController,
235             BroadcastDispatcher broadcastDispatcher,
236             UserTracker userTracker,
237             ConnectivityManager connectivityManager,
238             TelephonyManager telephonyManager,
239             TelephonyListenerManager telephonyListenerManager,
240             @Nullable WifiManager wifiManager,
241             AccessPointControllerImpl accessPointController,
242             StatusBarPipelineFlags statusBarPipelineFlags,
243             DemoModeController demoModeController,
244             CarrierConfigTracker carrierConfigTracker,
245             WifiStatusTrackerFactory trackerFactory,
246             MobileSignalControllerFactory mobileFactory,
247             @Main Handler handler,
248             InternetDialogManager internetDialogManager,
249             DumpManager dumpManager,
250             @StatusBarNetworkControllerLog LogBuffer logBuffer) {
251         this(context, connectivityManager,
252                 telephonyManager,
253                 telephonyListenerManager,
254                 wifiManager,
255                 subscriptionManager,
256                 Config.readConfig(context),
257                 bgLooper,
258                 bgExecutor,
259                 callbackHandler,
260                 accessPointController,
261                 statusBarPipelineFlags,
262                 new DataUsageController(context),
263                 new SubscriptionDefaults(),
264                 deviceProvisionedController,
265                 broadcastDispatcher,
266                 userTracker,
267                 demoModeController,
268                 carrierConfigTracker,
269                 trackerFactory,
270                 mobileFactory,
271                 handler,
272                 dumpManager,
273                 logBuffer);
274         mReceiverHandler.post(mRegisterListeners);
275         mInternetDialogManager = internetDialogManager;
276     }
277 
278     @VisibleForTesting
NetworkControllerImpl(Context context, ConnectivityManager connectivityManager, TelephonyManager telephonyManager, TelephonyListenerManager telephonyListenerManager, WifiManager wifiManager, SubscriptionManager subManager, Config config, Looper bgLooper, Executor bgExecutor, CallbackHandler callbackHandler, AccessPointControllerImpl accessPointController, StatusBarPipelineFlags statusBarPipelineFlags, DataUsageController dataUsageController, SubscriptionDefaults defaultsHandler, DeviceProvisionedController deviceProvisionedController, BroadcastDispatcher broadcastDispatcher, UserTracker userTracker, DemoModeController demoModeController, CarrierConfigTracker carrierConfigTracker, WifiStatusTrackerFactory trackerFactory, MobileSignalControllerFactory mobileFactory, @Main Handler handler, DumpManager dumpManager, LogBuffer logBuffer )279     NetworkControllerImpl(Context context, ConnectivityManager connectivityManager,
280             TelephonyManager telephonyManager,
281             TelephonyListenerManager telephonyListenerManager,
282             WifiManager wifiManager,
283             SubscriptionManager subManager,
284             Config config,
285             Looper bgLooper,
286             Executor bgExecutor,
287             CallbackHandler callbackHandler,
288             AccessPointControllerImpl accessPointController,
289             StatusBarPipelineFlags statusBarPipelineFlags,
290             DataUsageController dataUsageController,
291             SubscriptionDefaults defaultsHandler,
292             DeviceProvisionedController deviceProvisionedController,
293             BroadcastDispatcher broadcastDispatcher,
294             UserTracker userTracker,
295             DemoModeController demoModeController,
296             CarrierConfigTracker carrierConfigTracker,
297             WifiStatusTrackerFactory trackerFactory,
298             MobileSignalControllerFactory mobileFactory,
299             @Main Handler handler,
300             DumpManager dumpManager,
301             LogBuffer logBuffer
302     ) {
303         mContext = context;
304         mTelephonyListenerManager = telephonyListenerManager;
305         mConfig = config;
306         mMainHandler = handler;
307         mReceiverHandler = new Handler(bgLooper);
308         mBgLooper = bgLooper;
309         mBgExecutor = bgExecutor;
310         mCallbackHandler = callbackHandler;
311         mStatusBarPipelineFlags = statusBarPipelineFlags;
312         mDataSaverController = new DataSaverControllerImpl(context);
313         mBroadcastDispatcher = broadcastDispatcher;
314         mMobileFactory = mobileFactory;
315 
316         mSubscriptionManager = subManager;
317         mSubDefaults = defaultsHandler;
318         mConnectivityManager = connectivityManager;
319         mHasMobileDataFeature = telephonyManager.isDataCapable();
320         mDemoModeController = demoModeController;
321         mCarrierConfigTracker = carrierConfigTracker;
322         mDumpManager = dumpManager;
323         mLogBuffer = logBuffer;
324 
325         // telephony
326         mPhone = telephonyManager;
327 
328         // wifi
329         mWifiManager = wifiManager;
330 
331         mLocale = mContext.getResources().getConfiguration().locale;
332         mAccessPoints = accessPointController;
333         mDataUsageController = dataUsageController;
334         mDataUsageController.setNetworkController(this);
335         // TODO: Find a way to move this into DataUsageController.
336         mDataUsageController.setCallback(new DataUsageController.Callback() {
337             @Override
338             public void onMobileDataEnabled(boolean enabled) {
339                 mCallbackHandler.setMobileDataEnabled(enabled);
340                 notifyControllersMobileDataChanged();
341             }
342         });
343 
344         mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
345                 mCallbackHandler, this, mWifiManager, trackerFactory,
346                 mReceiverHandler);
347 
348         mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this);
349 
350         // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
351         updateAirplaneMode(true /* force callback */);
352         mUserTracker = userTracker;
353         mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(mMainHandler));
354 
355         deviceProvisionedController.addCallback(new DeviceProvisionedListener() {
356             @Override
357             public void onUserSetupChanged() {
358                 setUserSetupComplete(deviceProvisionedController.isCurrentUserSetup());
359             }
360         });
361         // Get initial user setup state
362         setUserSetupComplete(deviceProvisionedController.isCurrentUserSetup());
363 
364         WifiManager.ScanResultsCallback scanResultsCallback =
365                 new WifiManager.ScanResultsCallback() {
366             @Override
367             public void onScanResultsAvailable() {
368                 mNoNetworksAvailable = true;
369                 for (ScanResult scanResult : mWifiManager.getScanResults()) {
370                     if (!scanResult.SSID.equals(mWifiSignalController.getState().ssid)) {
371                         mNoNetworksAvailable = false;
372                         break;
373                     }
374                 }
375                 // Only update the network availability if there is no default network.
376                 if (mNoDefaultNetwork) {
377                     mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition,
378                             mNoNetworksAvailable);
379                 }
380             }
381         };
382 
383         if (mWifiManager != null) {
384             mWifiManager.registerScanResultsCallback(mReceiverHandler::post, scanResultsCallback);
385         }
386 
387         NetworkCallback callback =
388                 new NetworkCallback(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO){
389             private Network mLastNetwork;
390             private NetworkCapabilities mLastNetworkCapabilities;
391 
392             @Override
393             public void onLost(Network network) {
394                 mLastNetwork = null;
395                 mLastNetworkCapabilities = null;
396                 mLastDefaultNetworkCapabilities = null;
397                 String callback = new StringBuilder()
398                         .append(SSDF.format(System.currentTimeMillis())).append(",")
399                         .append("onLost: ")
400                         .append("network=").append(network)
401                         .toString();
402                 recordLastNetworkCallback(callback);
403                 updateConnectivity();
404             }
405 
406             @Override
407             public void onCapabilitiesChanged(
408                     Network network, NetworkCapabilities networkCapabilities) {
409                 boolean lastValidated = (mLastNetworkCapabilities != null)
410                         && mLastNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED);
411                 boolean validated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED);
412 
413                 // This callback is invoked a lot (i.e. when RSSI changes), so avoid updating
414                 // icons when connectivity state has remained the same.
415                 if (network.equals(mLastNetwork) && validated == lastValidated) {
416                     // Should not rely on getTransportTypes() returning the same order of transport
417                     // types. So sort the array before comparing.
418                     int[] newTypes = getProcessedTransportTypes(networkCapabilities);
419                     Arrays.sort(newTypes);
420 
421                     int[] lastTypes = (mLastNetworkCapabilities != null)
422                             ? getProcessedTransportTypes(mLastNetworkCapabilities) : null;
423                     if (lastTypes != null) Arrays.sort(lastTypes);
424 
425                     if (Arrays.equals(newTypes, lastTypes)) {
426                         return;
427                     }
428                 }
429                 mLastNetwork = network;
430                 mLastNetworkCapabilities = networkCapabilities;
431                 mLastDefaultNetworkCapabilities = networkCapabilities;
432                 String callback = new StringBuilder()
433                         .append(SSDF.format(System.currentTimeMillis())).append(",")
434                         .append("onCapabilitiesChanged: ")
435                         .append("network=").append(network).append(",")
436                         .append("networkCapabilities=").append(networkCapabilities)
437                         .toString();
438                 recordLastNetworkCallback(callback);
439                 updateConnectivity();
440             }
441         };
442         // Even though this callback runs on the receiver handler thread which also processes the
443         // CONNECTIVITY_ACTION broadcasts, the broadcast and callback might come in at different
444         // times. This is safe since updateConnectivity() builds the list of transports from
445         // scratch.
446         // TODO: Move off of the deprecated CONNECTIVITY_ACTION broadcast and rely on callbacks
447         // exclusively for status bar icons.
448         mConnectivityManager.registerDefaultNetworkCallback(callback, mReceiverHandler);
449         // Run the listener on our bg looper
450         mPhoneStateListener = subId -> {
451             mBgExecutor.execute(() -> {
452                 // For data switching from A to B, we assume B is validated for up to 2 seconds if:
453                 // 1) A and B are in the same subscription group e.g. CBRS data switch. And
454                 // 2) A was validated before the switch.
455                 // This is to provide smooth transition for UI without showing cross during data
456                 // switch.
457                 if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) {
458                     if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true.");
459                     mForceCellularValidated = true;
460                     mReceiverHandler.removeCallbacks(mClearForceValidated);
461                     mReceiverHandler.postDelayed(mClearForceValidated, 2000);
462                 }
463                 mActiveMobileDataSubscription = subId;
464                 doUpdateMobileControllers();
465             });
466         };
467 
468         // TODO(b/336357360): Until we can remove this class entirely, disable its handling of ALL
469         // demo mode commands, due to the fact that the mobile command handler has an infinite
470         // loop bug if you use any slot other than 1.
471         // mDemoModeController.addCallback(this);
472 
473         mDumpManager.registerNormalDumpable(TAG, this);
474     }
475 
476     private final Runnable mClearForceValidated = () -> {
477         if (DEBUG) Log.d(TAG, ": mClearForceValidated");
478         mForceCellularValidated = false;
479         updateConnectivity();
480     };
481 
isInGroupDataSwitch(int subId1, int subId2)482     boolean isInGroupDataSwitch(int subId1, int subId2) {
483         SubscriptionInfo info1 = mSubscriptionManager.getActiveSubscriptionInfo(subId1);
484         SubscriptionInfo info2 = mSubscriptionManager.getActiveSubscriptionInfo(subId2);
485         return (info1 != null && info2 != null && info1.getGroupUuid() != null
486             && info1.getGroupUuid().equals(info2.getGroupUuid()));
487     }
488 
keepCellularValidationBitInSwitch(int sourceSubId, int destSubId)489     boolean keepCellularValidationBitInSwitch(int sourceSubId, int destSubId) {
490         return mValidatedTransports.get(TRANSPORT_CELLULAR)
491                 && isInGroupDataSwitch(sourceSubId, destSubId);
492     }
493 
getDataSaverController()494     public DataSaverController getDataSaverController() {
495         return mDataSaverController;
496     }
497 
498     @VisibleForTesting
registerListeners()499     void registerListeners() {
500         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
501             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
502             mobileSignalController.registerListener();
503         }
504         if (mSubscriptionListener == null) {
505             mSubscriptionListener = new SubListener(mBgLooper);
506         }
507         mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
508         mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
509 
510         // broadcasts
511         IntentFilter filter = new IntentFilter();
512         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
513         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
514         filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
515         filter.addAction(Intent.ACTION_SERVICE_STATE);
516         filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
517         filter.addAction(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
518         filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
519         filter.addAction(TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
520         filter.addAction(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED);
521         filter.addAction(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED);
522         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
523         mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler);
524         mListening = true;
525 
526         // Initial setup of connectivity. Handled as if we had received a sticky broadcast of
527         // ConnectivityManager.CONNECTIVITY_ACTION.
528         mReceiverHandler.post(this::updateConnectivity);
529 
530         // Initial setup of WifiSignalController. Handled as if we had received a sticky broadcast
531         // of WifiManager.WIFI_STATE_CHANGED_ACTION or WifiManager.NETWORK_STATE_CHANGED_ACTION
532         mReceiverHandler.post(mWifiSignalController::fetchInitialState);
533 
534         // Initial setup of mLastServiceState. Only run if there is no service state yet.
535         // Each MobileSignalController will also get their corresponding
536         mReceiverHandler.post(() -> {
537             if (mLastServiceState == null) {
538                 mLastServiceState = mPhone.getServiceState();
539                 if (mMobileSignalControllers.size() == 0) {
540                     recalculateEmergency();
541                 }
542             }
543         });
544         updateMobileControllers();
545 
546         // Initial setup of emergency information. Handled as if we had received a sticky broadcast
547         // of TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED.
548         mReceiverHandler.post(this::recalculateEmergency);
549     }
550 
unregisterListeners()551     private void unregisterListeners() {
552         mListening = false;
553         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
554             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
555             mobileSignalController.unregisterListener();
556         }
557         mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener);
558         mBroadcastDispatcher.unregisterReceiver(this);
559     }
560 
561     @Override
getAccessPointController()562     public AccessPointController getAccessPointController() {
563         return mAccessPoints;
564     }
565 
566     @Override
getMobileDataController()567     public DataUsageController getMobileDataController() {
568         return mDataUsageController;
569     }
570 
571     /** */
addEmergencyListener(EmergencyListener listener)572     public void addEmergencyListener(EmergencyListener listener) {
573         mCallbackHandler.setListening(listener, true);
574         mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
575     }
576 
577     /** */
removeEmergencyListener(EmergencyListener listener)578     public void removeEmergencyListener(EmergencyListener listener) {
579         mCallbackHandler.setListening(listener, false);
580     }
581 
582     /** */
hasMobileDataFeature()583     public boolean hasMobileDataFeature() {
584         return mHasMobileDataFeature;
585     }
586 
587     /** */
hasVoiceCallingFeature()588     public boolean hasVoiceCallingFeature() {
589         return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
590     }
591 
getProcessedTransportTypes(NetworkCapabilities networkCapabilities)592     private int[] getProcessedTransportTypes(NetworkCapabilities networkCapabilities) {
593         int[] transportTypes = networkCapabilities.getTransportTypes();
594         for (int i = 0; i < transportTypes.length; i++) {
595             // For VCN over WiFi, the transportType is set to be TRANSPORT_CELLULAR in the
596             // NetworkCapabilities, but we need to convert it into TRANSPORT_WIFI in order to
597             // distinguish it from VCN over Cellular.
598             if (transportTypes[i] == NetworkCapabilities.TRANSPORT_CELLULAR
599                     && Utils.tryGetWifiInfoForVcn(mConnectivityManager, networkCapabilities)
600                             != null) {
601                 transportTypes[i] = NetworkCapabilities.TRANSPORT_WIFI;
602                 break;
603             }
604         }
605         return transportTypes;
606     }
607 
getDataController()608     private MobileSignalController getDataController() {
609         int dataSubId = mSubDefaults.getActiveDataSubId();
610         return getControllerWithSubId(dataSubId);
611     }
612 
getControllerWithSubId(int subId)613     private MobileSignalController getControllerWithSubId(int subId) {
614         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
615             if (DEBUG) Log.e(TAG, "No data sim selected");
616             return mDefaultSignalController;
617         }
618         if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
619             return mMobileSignalControllers.get(subId);
620         }
621         if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + subId);
622         return mDefaultSignalController;
623     }
624 
625     @Override
getMobileDataNetworkName()626     public String getMobileDataNetworkName() {
627         MobileSignalController controller = getDataController();
628         return controller != null ? controller.getState().networkNameData : "";
629     }
630 
631     @Override
isMobileDataNetworkInService()632     public boolean isMobileDataNetworkInService() {
633         MobileSignalController controller = getDataController();
634         return controller != null && controller.isInService();
635     }
636 
637     @Override
getNumberSubscriptions()638     public int getNumberSubscriptions() {
639         return mMobileSignalControllers.size();
640     }
641 
isDataControllerDisabled()642     boolean isDataControllerDisabled() {
643         MobileSignalController dataController = getDataController();
644         if (dataController == null) {
645             return false;
646         }
647 
648         return dataController.isDataDisabled();
649     }
650 
isCarrierMergedWifi(int subId)651     boolean isCarrierMergedWifi(int subId) {
652         return mWifiSignalController.isCarrierMergedWifi(subId);
653     }
654 
isEthernetDefault()655     boolean isEthernetDefault() {
656         return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
657     }
658 
getNetworkNameForCarrierWiFi(int subId)659     String getNetworkNameForCarrierWiFi(int subId) {
660         MobileSignalController controller = getControllerWithSubId(subId);
661         return controller != null ? controller.getNetworkNameForCarrierWiFi() : "";
662     }
663 
notifyControllersMobileDataChanged()664     private void notifyControllersMobileDataChanged() {
665         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
666             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
667             mobileSignalController.onMobileDataChanged();
668         }
669     }
670 
isEmergencyOnly()671     boolean isEmergencyOnly() {
672         if (mMobileSignalControllers.size() == 0) {
673             // When there are no active subscriptions, determine emengency state from last
674             // broadcast.
675             mEmergencySource = EMERGENCY_NO_CONTROLLERS;
676             return mLastServiceState != null && mLastServiceState.isEmergencyOnly();
677         }
678         int voiceSubId = mSubDefaults.getDefaultVoiceSubId();
679         if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) {
680             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
681                 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
682                 if (!mobileSignalController.getState().isEmergency) {
683                     mEmergencySource = EMERGENCY_FIRST_CONTROLLER
684                             + mobileSignalController.mSubscriptionInfo.getSubscriptionId();
685                     if (DEBUG) Log.d(TAG, "Found emergency " + mobileSignalController.mTag);
686                     return false;
687                 }
688             }
689         }
690         if (mMobileSignalControllers.indexOfKey(voiceSubId) >= 0) {
691             mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId;
692             if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId);
693             return mMobileSignalControllers.get(voiceSubId).getState().isEmergency;
694         }
695         // If we have the wrong subId but there is only one sim anyway, assume it should be the
696         // default.
697         if (mMobileSignalControllers.size() == 1) {
698             mEmergencySource = EMERGENCY_ASSUMED_VOICE_CONTROLLER
699                     + mMobileSignalControllers.keyAt(0);
700             if (DEBUG)  {
701                 Log.d(TAG, "Getting assumed emergency from "
702                         + mMobileSignalControllers.keyAt(0));
703             }
704             return mMobileSignalControllers.valueAt(0).getState().isEmergency;
705         }
706         if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
707         mEmergencySource = EMERGENCY_NO_SUB + voiceSubId;
708         // Something is wrong, better assume we can't make calls...
709         return true;
710     }
711 
712     /**
713      * Emergency status may have changed (triggered by MobileSignalController),
714      * so we should recheck and send out the state to listeners.
715      */
recalculateEmergency()716     void recalculateEmergency() {
717         mIsEmergency = isEmergencyOnly();
718         mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
719     }
720 
721     @Override
addCallback(@onNull SignalCallback cb)722     public void addCallback(@NonNull SignalCallback cb) {
723         cb.setSubs(mCurrentSubscriptions);
724         cb.setIsAirplaneMode(
725                 new IconState(
726                         mAirplaneMode,
727                         TelephonyIcons.FLIGHT_MODE_ICON,
728                         mContext.getString(R.string.accessibility_airplane_mode)));
729         cb.setNoSims(mHasNoSubs, mSimDetected);
730         cb.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition, mNoNetworksAvailable);
731         mWifiSignalController.notifyListeners(cb);
732         mEthernetSignalController.notifyListeners(cb);
733         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
734             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
735             mobileSignalController.notifyListeners(cb);
736         }
737         mCallbackHandler.setListening(cb, true);
738     }
739 
740     @Override
removeCallback(@onNull SignalCallback cb)741     public void removeCallback(@NonNull SignalCallback cb) {
742         mCallbackHandler.setListening(cb, false);
743     }
744 
745     @Override
setWifiEnabled(final boolean enabled)746     public void setWifiEnabled(final boolean enabled) {
747         new AsyncTask<Void, Void, Void>() {
748             @Override
749             protected Void doInBackground(Void... args) {
750                 mWifiManager.setWifiEnabled(enabled);
751                 return null;
752             }
753         }.execute();
754     }
755 
onUserSwitched(int newUserId)756     private void onUserSwitched(int newUserId) {
757         mCurrentUserId = newUserId;
758         mAccessPoints.onUserSwitched(newUserId);
759         updateConnectivity();
760     }
761 
762     @Override
onReceive(Context context, Intent intent)763     public void onReceive(Context context, Intent intent) {
764         if (CHATTY) {
765             Log.d(TAG, "onReceive: intent=" + intent);
766         }
767         final String action = intent.getAction();
768         mLogBuffer.log(
769                 TAG,
770                 LogLevel.INFO,
771                 logMessage -> {
772                     logMessage.setStr1(action);
773                     return Unit.INSTANCE;
774                 },
775                 logMessage -> String.format(
776                         Locale.US,
777                         "Received broadcast with action \"%s\"",
778                         logMessage.getStr1()));
779         switch (action) {
780             case ConnectivityManager.CONNECTIVITY_ACTION:
781                 updateConnectivity();
782                 break;
783             case Intent.ACTION_AIRPLANE_MODE_CHANGED:
784                 refreshLocale();
785                 updateAirplaneMode(false);
786                 break;
787             case TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED:
788                 // We are using different subs now, we might be able to make calls.
789                 recalculateEmergency();
790                 break;
791             case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
792                 // Notify every MobileSignalController so they can know whether they are the
793                 // data sim or not.
794                 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
795                     MobileSignalController controller = mMobileSignalControllers.valueAt(i);
796                     controller.handleBroadcast(intent);
797                 }
798                 mConfig = Config.readConfig(mContext);
799                 mReceiverHandler.post(this::handleConfigurationChanged);
800                 break;
801 
802             case TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED: {
803                 // Notify the relevant MobileSignalController of the change
804                 int subId = intent.getIntExtra(
805                         TelephonyManager.EXTRA_SUBSCRIPTION_ID,
806                         INVALID_SUBSCRIPTION_ID
807                 );
808                 if (SubscriptionManager.isValidSubscriptionId(subId)) {
809                     if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
810                         mMobileSignalControllers.get(subId).handleBroadcast(intent);
811                     }
812                 }
813             }
814             break;
815             case Intent.ACTION_SIM_STATE_CHANGED:
816                 // Avoid rebroadcast because SysUI is direct boot aware.
817                 if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
818                     break;
819                 }
820                 // Might have different subscriptions now.
821                 updateMobileControllers();
822                 break;
823             case Intent.ACTION_SERVICE_STATE:
824                 mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
825                 if (mMobileSignalControllers.size() == 0) {
826                     // If none of the subscriptions are active, we might need to recalculate
827                     // emergency state.
828                     recalculateEmergency();
829                 }
830                 break;
831             case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
832                 mConfig = Config.readConfig(mContext);
833                 mReceiverHandler.post(this::handleConfigurationChanged);
834                 break;
835             case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
836                 mMainHandler.post(() -> mInternetDialogManager.create(true,
837                         mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi(),
838                         null /* view */));
839                 break;
840             default:
841                 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
842                         INVALID_SUBSCRIPTION_ID);
843                 if (SubscriptionManager.isValidSubscriptionId(subId)) {
844                     if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
845                         mMobileSignalControllers.get(subId).handleBroadcast(intent);
846                     } else {
847                         // Can't find this subscription...  We must be out of date.
848                         updateMobileControllers();
849                     }
850                 } else {
851                     // No sub id, must be for the wifi.
852                     mWifiSignalController.handleBroadcast(intent);
853                 }
854                 break;
855         }
856     }
857 
858     @VisibleForTesting
handleConfigurationChanged()859     void handleConfigurationChanged() {
860         updateMobileControllers();
861         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
862             MobileSignalController controller = mMobileSignalControllers.valueAt(i);
863             controller.setConfiguration(mConfig);
864         }
865         refreshLocale();
866     }
867 
updateMobileControllers()868     private void updateMobileControllers() {
869         if (!mListening) {
870             return;
871         }
872         doUpdateMobileControllers();
873     }
874 
filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions)875     private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
876         if (subscriptions.size() == 2) {
877             SubscriptionInfo info1 = subscriptions.get(0);
878             SubscriptionInfo info2 = subscriptions.get(1);
879             if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
880                 // If both subscriptions are primary, show both.
881                 if (!info1.isOpportunistic() && !info2.isOpportunistic()) return;
882 
883                 // If carrier required, always show signal bar of primary subscription.
884                 // Otherwise, show whichever subscription is currently active for Internet.
885                 boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig()
886                         .getBoolean(CarrierConfigManager
887                         .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN);
888                 if (alwaysShowPrimary) {
889                     subscriptions.remove(info1.isOpportunistic() ? info1 : info2);
890                 } else {
891                     subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription
892                             ? info2 : info1);
893                 }
894             }
895         }
896     }
897 
898     @VisibleForTesting
doUpdateMobileControllers()899     void doUpdateMobileControllers() {
900         List<SubscriptionInfo> subscriptions = mSubscriptionManager
901                 .getCompleteActiveSubscriptionInfoList();
902         if (subscriptions == null) {
903             subscriptions = Collections.emptyList();
904         }
905 
906         filterMobileSubscriptionInSameGroup(subscriptions);
907 
908         // If there have been no relevant changes to any of the subscriptions, we can leave as is.
909         if (hasCorrectMobileControllers(subscriptions)) {
910             // Even if the controllers are correct, make sure we have the right no sims state.
911             // Such as on boot, don't need any controllers, because there are no sims,
912             // but we still need to update the no sim state.
913             updateNoSims();
914             return;
915         }
916         synchronized (mLock) {
917             setCurrentSubscriptionsLocked(subscriptions);
918         }
919         updateNoSims();
920         recalculateEmergency();
921     }
922 
923     @VisibleForTesting
updateNoSims()924     protected void updateNoSims() {
925         boolean hasNoSubs = mHasMobileDataFeature && mMobileSignalControllers.size() == 0;
926         boolean simDetected = hasAnySim();
927         if (hasNoSubs != mHasNoSubs || simDetected != mSimDetected) {
928             mHasNoSubs = hasNoSubs;
929             mSimDetected = simDetected;
930             mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
931         }
932     }
933 
hasAnySim()934     private boolean hasAnySim() {
935         int simCount = mPhone.getActiveModemCount();
936         for (int i = 0; i < simCount; i++) {
937             int state = mPhone.getSimState(i);
938             if (state != TelephonyManager.SIM_STATE_ABSENT
939                     && state != TelephonyManager.SIM_STATE_UNKNOWN) {
940                 return true;
941             }
942         }
943         return false;
944     }
945 
946     @GuardedBy("mLock")
947     @VisibleForTesting
setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions)948     void setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions) {
949         Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() {
950             @Override
951             public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) {
952                 return lhs.getSimSlotIndex() == rhs.getSimSlotIndex()
953                         ? lhs.getSubscriptionId() - rhs.getSubscriptionId()
954                         : lhs.getSimSlotIndex() - rhs.getSimSlotIndex();
955             }
956         });
957         Log.i(
958                 TAG,
959                 String.format(
960                         Locale.US,
961                         "Subscriptions changed: %s",
962                         createSubscriptionChangeStatement(mCurrentSubscriptions, subscriptions)));
963         mCurrentSubscriptions = subscriptions;
964 
965         SparseArray<MobileSignalController> cachedControllers =
966                 new SparseArray<MobileSignalController>();
967         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
968             cachedControllers.put(mMobileSignalControllers.keyAt(i),
969                     mMobileSignalControllers.valueAt(i));
970         }
971         mMobileSignalControllers.clear();
972         final int num = subscriptions.size();
973         for (int i = 0; i < num; i++) {
974             int subId = subscriptions.get(i).getSubscriptionId();
975             // If we have a copy of this controller already reuse it, otherwise make a new one.
976             if (cachedControllers.indexOfKey(subId) >= 0) {
977                 mMobileSignalControllers.put(subId, cachedControllers.get(subId));
978                 cachedControllers.remove(subId);
979             } else {
980                 MobileSignalController controller = mMobileFactory.createMobileSignalController(
981                         mConfig,
982                         mHasMobileDataFeature,
983                         mPhone.createForSubscriptionId(subId),
984                         this,
985                         subscriptions.get(i),
986                         mSubDefaults,
987                         mReceiverHandler.getLooper()
988                 );
989                 controller.setUserSetupComplete(mUserSetup);
990                 mMobileSignalControllers.put(subId, controller);
991                 if (subscriptions.get(i).getSimSlotIndex() == 0) {
992                     mDefaultSignalController = controller;
993                 }
994                 if (mListening) {
995                     controller.registerListener();
996                 }
997             }
998         }
999         if (mListening) {
1000             for (int i = 0; i < cachedControllers.size(); i++) {
1001                 int key = cachedControllers.keyAt(i);
1002                 if (cachedControllers.get(key) == mDefaultSignalController) {
1003                     mDefaultSignalController = null;
1004                 }
1005                 cachedControllers.get(key).unregisterListener();
1006             }
1007         }
1008         mCallbackHandler.setSubs(subscriptions);
1009         notifyAllListeners();
1010 
1011         // There may be new MobileSignalControllers around, make sure they get the current
1012         // inet condition and airplane mode.
1013         pushConnectivityToSignals();
1014         updateAirplaneMode(true /* force */);
1015     }
1016 
setUserSetupComplete(final boolean userSetup)1017     private void setUserSetupComplete(final boolean userSetup) {
1018         mReceiverHandler.post(() -> handleSetUserSetupComplete(userSetup));
1019     }
1020 
handleSetUserSetupComplete(boolean userSetup)1021     private void handleSetUserSetupComplete(boolean userSetup) {
1022         mUserSetup = userSetup;
1023         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1024             MobileSignalController controller = mMobileSignalControllers.valueAt(i);
1025             controller.setUserSetupComplete(mUserSetup);
1026         }
1027     }
1028 
1029     @VisibleForTesting
isUserSetup()1030     boolean isUserSetup() {
1031         return mUserSetup;
1032     }
1033 
1034     @VisibleForTesting
hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions)1035     boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) {
1036         if (allSubscriptions.size() != mMobileSignalControllers.size()) {
1037             return false;
1038         }
1039         for (SubscriptionInfo info : allSubscriptions) {
1040             if (mMobileSignalControllers.indexOfKey(info.getSubscriptionId()) < 0) {
1041                 return false;
1042             }
1043         }
1044         return true;
1045     }
1046 
1047     @VisibleForTesting
setNoNetworksAvailable(boolean noNetworksAvailable)1048     void setNoNetworksAvailable(boolean noNetworksAvailable) {
1049         mNoNetworksAvailable = noNetworksAvailable;
1050     }
1051 
updateAirplaneMode(boolean force)1052     private void updateAirplaneMode(boolean force) {
1053         boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
1054                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
1055         if (airplaneMode != mAirplaneMode || force) {
1056             mAirplaneMode = airplaneMode;
1057             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1058                 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
1059                 mobileSignalController.setAirplaneMode(mAirplaneMode);
1060             }
1061             notifyListeners();
1062         }
1063     }
1064 
refreshLocale()1065     private void refreshLocale() {
1066         Locale current = mContext.getResources().getConfiguration().locale;
1067         if (!current.equals(mLocale)) {
1068             mLocale = current;
1069             mWifiSignalController.refreshLocale();
1070             notifyAllListeners();
1071         }
1072     }
1073 
1074     /**
1075      * Forces update of all callbacks on both SignalClusters and
1076      * NetworkSignalChangedCallbacks.
1077      */
notifyAllListeners()1078     private void notifyAllListeners() {
1079         notifyListeners();
1080         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1081             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
1082             mobileSignalController.notifyListeners();
1083         }
1084         mWifiSignalController.notifyListeners();
1085         mEthernetSignalController.notifyListeners();
1086     }
1087 
1088     /**
1089      * Notifies listeners of changes in state of to the NetworkController, but
1090      * does not notify for any info on SignalControllers, for that call
1091      * notifyAllListeners.
1092      */
notifyListeners()1093     private void notifyListeners() {
1094         mCallbackHandler.setIsAirplaneMode(
1095                 new IconState(
1096                         mAirplaneMode,
1097                         TelephonyIcons.FLIGHT_MODE_ICON,
1098                         mContext.getString(R.string.accessibility_airplane_mode)));
1099         mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
1100     }
1101 
1102     /**
1103      * Update the Inet conditions and what network we are connected to.
1104      */
updateConnectivity()1105     private void updateConnectivity() {
1106         mConnectedTransports.clear();
1107         mValidatedTransports.clear();
1108         if (mLastDefaultNetworkCapabilities != null) {
1109             for (int transportType : mLastDefaultNetworkCapabilities.getTransportTypes()) {
1110                 if (transportType != NetworkCapabilities.TRANSPORT_CELLULAR
1111                         && transportType != NetworkCapabilities.TRANSPORT_WIFI
1112                         && transportType != NetworkCapabilities.TRANSPORT_ETHERNET) {
1113                     continue;
1114                 }
1115                 if (transportType == NetworkCapabilities.TRANSPORT_CELLULAR
1116                         && Utils.tryGetWifiInfoForVcn(
1117                                         mConnectivityManager, mLastDefaultNetworkCapabilities)
1118                                 != null) {
1119                     mConnectedTransports.set(NetworkCapabilities.TRANSPORT_WIFI);
1120                     if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
1121                         mValidatedTransports.set(NetworkCapabilities.TRANSPORT_WIFI);
1122                     }
1123                 } else {
1124                     mConnectedTransports.set(transportType);
1125                     if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
1126                         mValidatedTransports.set(transportType);
1127                     }
1128                 }
1129             }
1130         }
1131 
1132         if (mForceCellularValidated) mValidatedTransports.set(TRANSPORT_CELLULAR);
1133 
1134         if (CHATTY) {
1135             Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports);
1136             Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
1137         }
1138 
1139         mInetCondition = mValidatedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
1140                 || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
1141                 || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
1142 
1143         pushConnectivityToSignals();
1144         mNoDefaultNetwork = !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
1145                 && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
1146                 && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
1147         mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition,
1148                 mNoNetworksAvailable);
1149     }
1150 
1151     /**
1152      * Pushes the current connectivity state to all SignalControllers.
1153      */
pushConnectivityToSignals()1154     private void pushConnectivityToSignals() {
1155         // We want to update all the icons, all at once, for any condition change
1156         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1157             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
1158             mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
1159         }
1160         mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
1161         mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
1162     }
1163 
1164     /** */
1165     @NeverCompile
dump(PrintWriter pw, String[] args)1166     public void dump(PrintWriter pw, String[] args) {
1167         pw.println("NetworkController state:");
1168         pw.println("  mUserSetup=" + mUserSetup);
1169 
1170         pw.println("  - telephony ------");
1171         pw.print("  hasVoiceCallingFeature()=");
1172         pw.println(hasVoiceCallingFeature());
1173         pw.println("  mListening=" + mListening);
1174         pw.println("  mActiveMobileDataSubscription=" + mActiveMobileDataSubscription);
1175 
1176         pw.println("  - connectivity ------");
1177         pw.print("  mConnectedTransports=");
1178         pw.println(mConnectedTransports);
1179         pw.print("  mValidatedTransports=");
1180         pw.println(mValidatedTransports);
1181         pw.print("  mInetCondition=");
1182         pw.println(mInetCondition);
1183         pw.print("  mAirplaneMode=");
1184         pw.println(mAirplaneMode);
1185         pw.print("  mLocale=");
1186         pw.println(mLocale);
1187         pw.print("  mLastServiceState=");
1188         pw.println(mLastServiceState);
1189         pw.print("  mIsEmergency=");
1190         pw.println(mIsEmergency);
1191         pw.print("  mEmergencySource=");
1192         pw.println(emergencyToString(mEmergencySource));
1193 
1194         pw.println("  - DefaultNetworkCallback -----");
1195         int size = 0;
1196         for (int i = 0; i < HISTORY_SIZE; i++) {
1197             if (mHistory[i] != null) {
1198                 size++;
1199             }
1200         }
1201         for (int i = mHistoryIndex + HISTORY_SIZE - 1;
1202                 i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
1203             pw.println("  Previous NetworkCallback(" + (mHistoryIndex + HISTORY_SIZE - i) + "): "
1204                     + mHistory[i & (HISTORY_SIZE - 1)]);
1205         }
1206 
1207         pw.println("  - config ------");
1208         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1209             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
1210             mobileSignalController.dump(pw);
1211         }
1212         mWifiSignalController.dump(pw);
1213 
1214         mEthernetSignalController.dump(pw);
1215 
1216         mAccessPoints.dump(pw);
1217 
1218         mCallbackHandler.dump(pw);
1219     }
1220 
emergencyToString(int emergencySource)1221     private static String emergencyToString(int emergencySource) {
1222         if (emergencySource > EMERGENCY_NO_SUB) {
1223             return "ASSUMED_VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER)
1224                     + ")";
1225         } else if (emergencySource > EMERGENCY_NO_SUB) {
1226             return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")";
1227         } else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) {
1228             return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")";
1229         } else if (emergencySource > EMERGENCY_FIRST_CONTROLLER) {
1230             return "FIRST_CONTROLLER(" + (emergencySource - EMERGENCY_FIRST_CONTROLLER) + ")";
1231         } else if (emergencySource == EMERGENCY_NO_CONTROLLERS) {
1232             return "NO_CONTROLLERS";
1233         }
1234         return "UNKNOWN_SOURCE";
1235     }
1236 
1237     private boolean mDemoInetCondition;
1238 
1239     @Override
onDemoModeStarted()1240     public void onDemoModeStarted() {
1241         if (DEBUG) Log.d(TAG, "Entering demo mode");
1242         unregisterListeners();
1243         mDemoInetCondition = mInetCondition;
1244     }
1245 
1246     @Override
onDemoModeFinished()1247     public void onDemoModeFinished() {
1248         if (DEBUG) Log.d(TAG, "Exiting demo mode");
1249         // Update what MobileSignalControllers, because they may change
1250         // to set the number of sim slots.
1251         updateMobileControllers();
1252         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1253             MobileSignalController controller = mMobileSignalControllers.valueAt(i);
1254             controller.resetLastState();
1255         }
1256         mWifiSignalController.resetLastState();
1257         mReceiverHandler.post(mRegisterListeners);
1258         notifyAllListeners();
1259     }
1260 
1261     @Override
dispatchDemoCommand(String command, Bundle args)1262     public void dispatchDemoCommand(String command, Bundle args) {
1263         if (!mDemoModeController.isInDemoMode()) {
1264             return;
1265         }
1266 
1267         String airplane = args.getString("airplane");
1268         if (airplane != null) {
1269             boolean show = airplane.equals("show");
1270             mCallbackHandler.setIsAirplaneMode(
1271                     new IconState(
1272                             show,
1273                             TelephonyIcons.FLIGHT_MODE_ICON,
1274                             mContext.getString(R.string.accessibility_airplane_mode)));
1275         }
1276         String fully = args.getString("fully");
1277         if (fully != null) {
1278             mDemoInetCondition = Boolean.parseBoolean(fully);
1279             BitSet connected = new BitSet();
1280 
1281             if (mDemoInetCondition) {
1282                 connected.set(mWifiSignalController.mTransportType);
1283             }
1284             mWifiSignalController.updateConnectivity(connected, connected);
1285             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1286                 MobileSignalController controller = mMobileSignalControllers.valueAt(i);
1287                 if (mDemoInetCondition) {
1288                     connected.set(controller.mTransportType);
1289                 }
1290                 controller.updateConnectivity(connected, connected);
1291             }
1292         }
1293         String sims = args.getString("sims");
1294         if (sims != null) {
1295             int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8);
1296             List<SubscriptionInfo> subs = new ArrayList<>();
1297             if (num != mMobileSignalControllers.size()) {
1298                 mMobileSignalControllers.clear();
1299                 int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
1300                 for (int i = start /* get out of normal index range */; i < start + num; i++) {
1301                     subs.add(addDemoModeSignalController(i, i));
1302                 }
1303                 mCallbackHandler.setSubs(subs);
1304                 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1305                     int key = mMobileSignalControllers.keyAt(i);
1306                     MobileSignalController controller = mMobileSignalControllers.get(key);
1307                     controller.notifyListeners();
1308                 }
1309             }
1310         }
1311         String nosim = args.getString("nosim");
1312         if (nosim != null) {
1313             mHasNoSubs = nosim.equals("show");
1314             mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
1315         }
1316         String mobile = args.getString("mobile");
1317         if (mobile != null) {
1318             boolean show = mobile.equals("show");
1319             String datatype = args.getString("datatype");
1320             String slotString = args.getString("slot");
1321             int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString);
1322             slot = MathUtils.constrain(slot, 0, 8);
1323             String carrierIdString = args.getString("carrierid");
1324             int carrierId = TextUtils.isEmpty(carrierIdString) ? 0
1325                     : Integer.parseInt(carrierIdString);
1326             // Ensure we have enough sim slots
1327             // TODO(b/336357360): This is the origination of the infinite loop bug, for those
1328             // following along at home.
1329             List<SubscriptionInfo> subs = new ArrayList<>();
1330             while (mMobileSignalControllers.size() <= slot) {
1331                 int nextSlot = mMobileSignalControllers.size();
1332                 subs.add(addDemoModeSignalController(nextSlot, nextSlot));
1333             }
1334             if (!subs.isEmpty()) {
1335                 mCallbackHandler.setSubs(subs);
1336             }
1337             // Hack to index linearly for easy use.
1338             MobileSignalController controller = mMobileSignalControllers.valueAt(slot);
1339             if (carrierId != 0) {
1340                 controller.getState().setCarrierId(carrierId);
1341             }
1342             controller.getState().dataSim = datatype != null;
1343             controller.getState().isDefault = datatype != null;
1344             controller.getState().dataConnected = datatype != null;
1345             if (datatype != null) {
1346                 controller.getState().iconGroup =
1347                         datatype.equals("1x") ? TelephonyIcons.ONE_X :
1348                         datatype.equals("3g") ? TelephonyIcons.THREE_G :
1349                         datatype.equals("4g") ? TelephonyIcons.FOUR_G :
1350                         datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS :
1351                         datatype.equals("5g") ? TelephonyIcons.NR_5G :
1352                         datatype.equals("5ge") ? TelephonyIcons.LTE_CA_5G_E :
1353                         datatype.equals("5g+") ? TelephonyIcons.NR_5G_PLUS :
1354                         datatype.equals("e") ? TelephonyIcons.E :
1355                         datatype.equals("g") ? TelephonyIcons.G :
1356                         datatype.equals("h") ? TelephonyIcons.H :
1357                         datatype.equals("h+") ? TelephonyIcons.H_PLUS :
1358                         datatype.equals("lte") ? TelephonyIcons.LTE :
1359                         datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS :
1360                         datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED :
1361                         datatype.equals("not") ? TelephonyIcons.NOT_DEFAULT_DATA :
1362                         TelephonyIcons.UNKNOWN;
1363             }
1364             if (args.containsKey("roam")) {
1365                 controller.getState().roaming = "show".equals(args.getString("roam"));
1366             }
1367             String level = args.getString("level");
1368             if (level != null) {
1369                 controller.getState().level = level.equals("null") ? -1
1370                         : Math.min(Integer.parseInt(level),
1371                                 CellSignalStrength.getNumSignalStrengthLevels());
1372                 controller.getState().connected = controller.getState().level >= 0;
1373             }
1374             if (args.containsKey("inflate")) {
1375                 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1376                     mMobileSignalControllers.valueAt(i).mInflateSignalStrengths =
1377                             "true".equals(args.getString("inflate"));
1378                 }
1379             }
1380             String activity = args.getString("activity");
1381             if (activity != null) {
1382                 controller.getState().dataConnected = true;
1383                 switch (activity) {
1384                     case "inout":
1385                         controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
1386                         break;
1387                     case "in":
1388                         controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN);
1389                         break;
1390                     case "out":
1391                         controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT);
1392                         break;
1393                     default:
1394                         controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
1395                         break;
1396                 }
1397             } else {
1398                 controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
1399             }
1400             controller.getState().enabled = show;
1401             controller.notifyListeners();
1402         }
1403         String carrierNetworkChange = args.getString("carriernetworkchange");
1404         if (carrierNetworkChange != null) {
1405             boolean show = carrierNetworkChange.equals("show");
1406             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1407                 MobileSignalController controller = mMobileSignalControllers.valueAt(i);
1408                 controller.setCarrierNetworkChangeMode(show);
1409             }
1410         }
1411     }
1412 
1413     @Override
demoCommands()1414     public List<String> demoCommands() {
1415         List<String> s = new ArrayList<>();
1416         s.add(DemoMode.COMMAND_NETWORK);
1417         return s;
1418     }
1419 
recordLastNetworkCallback(String callback)1420     private void recordLastNetworkCallback(String callback) {
1421         mHistory[mHistoryIndex] = callback;
1422         mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
1423     }
1424 
addDemoModeSignalController(int id, int simSlotIndex)1425     private SubscriptionInfo addDemoModeSignalController(int id, int simSlotIndex) {
1426         SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
1427                 null, null, null, "", false, null, null);
1428 
1429         MobileSignalController controller = mMobileFactory.createMobileSignalController(
1430                 mConfig,
1431                 mHasMobileDataFeature,
1432                 mPhone.createForSubscriptionId(info.getSubscriptionId()),
1433                 this,
1434                 info,
1435                 mSubDefaults,
1436                 mReceiverHandler.getLooper()
1437         );
1438 
1439         mMobileSignalControllers.put(id, controller);
1440         controller.getState().userSetup = true;
1441         return info;
1442     }
1443 
1444     /** */
isRadioOn()1445     public boolean isRadioOn() {
1446         return !mAirplaneMode;
1447     }
1448 
1449     private class SubListener extends OnSubscriptionsChangedListener {
SubListener(Looper looper)1450         SubListener(Looper looper) {
1451             super(looper);
1452         }
1453 
1454         @Override
onSubscriptionsChanged()1455         public void onSubscriptionsChanged() {
1456             updateMobileControllers();
1457         }
1458     }
1459 
1460     /**
1461      * Used to register listeners from the BG Looper, this way the PhoneStateListeners that
1462      * get created will also run on the BG Looper.
1463      */
1464     private final Runnable mRegisterListeners = () -> registerListeners();
1465 
1466     /** Returns a logging statement for the given old and new list of {@link SubscriptionInfo} */
createSubscriptionChangeStatement( final @Nullable List<SubscriptionInfo> oldSubscriptions, final @Nullable List<SubscriptionInfo> newSubscriptions)1467     private static String createSubscriptionChangeStatement(
1468             final @Nullable List<SubscriptionInfo> oldSubscriptions,
1469             final @Nullable List<SubscriptionInfo> newSubscriptions) {
1470         return String.format(
1471                 Locale.US,
1472                 "old=%s, new=%s",
1473                 toSubscriptionIds(oldSubscriptions),
1474                 toSubscriptionIds(newSubscriptions));
1475     }
1476 
1477     /** Returns to a list of subscription IDs for the given list of {@link SubscriptionInfo} */
1478     @Nullable
toSubscriptionIds( final @Nullable List<SubscriptionInfo> subscriptions)1479     private static List<Integer> toSubscriptionIds(
1480             final @Nullable List<SubscriptionInfo> subscriptions) {
1481         return subscriptions != null ? subscriptions.stream().map(
1482                 SubscriptionInfo::getSubscriptionId).collect(Collectors.toList()) : null;
1483     }
1484 }
1485