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(networkCapabilities) != null) {
600                 transportTypes[i] = NetworkCapabilities.TRANSPORT_WIFI;
601                 break;
602             }
603         }
604         return transportTypes;
605     }
606 
getDataController()607     private MobileSignalController getDataController() {
608         int dataSubId = mSubDefaults.getActiveDataSubId();
609         return getControllerWithSubId(dataSubId);
610     }
611 
getControllerWithSubId(int subId)612     private MobileSignalController getControllerWithSubId(int subId) {
613         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
614             if (DEBUG) Log.e(TAG, "No data sim selected");
615             return mDefaultSignalController;
616         }
617         if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
618             return mMobileSignalControllers.get(subId);
619         }
620         if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + subId);
621         return mDefaultSignalController;
622     }
623 
624     @Override
getMobileDataNetworkName()625     public String getMobileDataNetworkName() {
626         MobileSignalController controller = getDataController();
627         return controller != null ? controller.getState().networkNameData : "";
628     }
629 
630     @Override
isMobileDataNetworkInService()631     public boolean isMobileDataNetworkInService() {
632         MobileSignalController controller = getDataController();
633         return controller != null && controller.isInService();
634     }
635 
636     @Override
getNumberSubscriptions()637     public int getNumberSubscriptions() {
638         return mMobileSignalControllers.size();
639     }
640 
isDataControllerDisabled()641     boolean isDataControllerDisabled() {
642         MobileSignalController dataController = getDataController();
643         if (dataController == null) {
644             return false;
645         }
646 
647         return dataController.isDataDisabled();
648     }
649 
isCarrierMergedWifi(int subId)650     boolean isCarrierMergedWifi(int subId) {
651         return mWifiSignalController.isCarrierMergedWifi(subId);
652     }
653 
isEthernetDefault()654     boolean isEthernetDefault() {
655         return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
656     }
657 
getNetworkNameForCarrierWiFi(int subId)658     String getNetworkNameForCarrierWiFi(int subId) {
659         MobileSignalController controller = getControllerWithSubId(subId);
660         return controller != null ? controller.getNetworkNameForCarrierWiFi() : "";
661     }
662 
notifyControllersMobileDataChanged()663     private void notifyControllersMobileDataChanged() {
664         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
665             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
666             mobileSignalController.onMobileDataChanged();
667         }
668     }
669 
isEmergencyOnly()670     boolean isEmergencyOnly() {
671         if (mMobileSignalControllers.size() == 0) {
672             // When there are no active subscriptions, determine emengency state from last
673             // broadcast.
674             mEmergencySource = EMERGENCY_NO_CONTROLLERS;
675             return mLastServiceState != null && mLastServiceState.isEmergencyOnly();
676         }
677         int voiceSubId = mSubDefaults.getDefaultVoiceSubId();
678         if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) {
679             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
680                 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
681                 if (!mobileSignalController.getState().isEmergency) {
682                     mEmergencySource = EMERGENCY_FIRST_CONTROLLER
683                             + mobileSignalController.mSubscriptionInfo.getSubscriptionId();
684                     if (DEBUG) Log.d(TAG, "Found emergency " + mobileSignalController.mTag);
685                     return false;
686                 }
687             }
688         }
689         if (mMobileSignalControllers.indexOfKey(voiceSubId) >= 0) {
690             mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId;
691             if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId);
692             return mMobileSignalControllers.get(voiceSubId).getState().isEmergency;
693         }
694         // If we have the wrong subId but there is only one sim anyway, assume it should be the
695         // default.
696         if (mMobileSignalControllers.size() == 1) {
697             mEmergencySource = EMERGENCY_ASSUMED_VOICE_CONTROLLER
698                     + mMobileSignalControllers.keyAt(0);
699             if (DEBUG)  {
700                 Log.d(TAG, "Getting assumed emergency from "
701                         + mMobileSignalControllers.keyAt(0));
702             }
703             return mMobileSignalControllers.valueAt(0).getState().isEmergency;
704         }
705         if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
706         mEmergencySource = EMERGENCY_NO_SUB + voiceSubId;
707         // Something is wrong, better assume we can't make calls...
708         return true;
709     }
710 
711     /**
712      * Emergency status may have changed (triggered by MobileSignalController),
713      * so we should recheck and send out the state to listeners.
714      */
recalculateEmergency()715     void recalculateEmergency() {
716         mIsEmergency = isEmergencyOnly();
717         mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
718     }
719 
720     @Override
addCallback(@onNull SignalCallback cb)721     public void addCallback(@NonNull SignalCallback cb) {
722         cb.setSubs(mCurrentSubscriptions);
723         cb.setIsAirplaneMode(
724                 new IconState(
725                         mAirplaneMode,
726                         TelephonyIcons.FLIGHT_MODE_ICON,
727                         mContext.getString(R.string.accessibility_airplane_mode)));
728         cb.setNoSims(mHasNoSubs, mSimDetected);
729         cb.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition, mNoNetworksAvailable);
730         mWifiSignalController.notifyListeners(cb);
731         mEthernetSignalController.notifyListeners(cb);
732         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
733             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
734             mobileSignalController.notifyListeners(cb);
735         }
736         mCallbackHandler.setListening(cb, true);
737     }
738 
739     @Override
removeCallback(@onNull SignalCallback cb)740     public void removeCallback(@NonNull SignalCallback cb) {
741         mCallbackHandler.setListening(cb, false);
742     }
743 
744     @Override
setWifiEnabled(final boolean enabled)745     public void setWifiEnabled(final boolean enabled) {
746         new AsyncTask<Void, Void, Void>() {
747             @Override
748             protected Void doInBackground(Void... args) {
749                 mWifiManager.setWifiEnabled(enabled);
750                 return null;
751             }
752         }.execute();
753     }
754 
onUserSwitched(int newUserId)755     private void onUserSwitched(int newUserId) {
756         mCurrentUserId = newUserId;
757         mAccessPoints.onUserSwitched(newUserId);
758         updateConnectivity();
759     }
760 
761     @Override
onReceive(Context context, Intent intent)762     public void onReceive(Context context, Intent intent) {
763         if (CHATTY) {
764             Log.d(TAG, "onReceive: intent=" + intent);
765         }
766         final String action = intent.getAction();
767         mLogBuffer.log(
768                 TAG,
769                 LogLevel.INFO,
770                 logMessage -> {
771                     logMessage.setStr1(action);
772                     return Unit.INSTANCE;
773                 },
774                 logMessage -> String.format(
775                         Locale.US,
776                         "Received broadcast with action \"%s\"",
777                         logMessage.getStr1()));
778         switch (action) {
779             case ConnectivityManager.CONNECTIVITY_ACTION:
780                 updateConnectivity();
781                 break;
782             case Intent.ACTION_AIRPLANE_MODE_CHANGED:
783                 refreshLocale();
784                 updateAirplaneMode(false);
785                 break;
786             case TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED:
787                 // We are using different subs now, we might be able to make calls.
788                 recalculateEmergency();
789                 break;
790             case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
791                 // Notify every MobileSignalController so they can know whether they are the
792                 // data sim or not.
793                 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
794                     MobileSignalController controller = mMobileSignalControllers.valueAt(i);
795                     controller.handleBroadcast(intent);
796                 }
797                 mConfig = Config.readConfig(mContext);
798                 mReceiverHandler.post(this::handleConfigurationChanged);
799                 break;
800 
801             case TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED: {
802                 // Notify the relevant MobileSignalController of the change
803                 int subId = intent.getIntExtra(
804                         TelephonyManager.EXTRA_SUBSCRIPTION_ID,
805                         INVALID_SUBSCRIPTION_ID
806                 );
807                 if (SubscriptionManager.isValidSubscriptionId(subId)) {
808                     if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
809                         mMobileSignalControllers.get(subId).handleBroadcast(intent);
810                     }
811                 }
812             }
813             break;
814             case Intent.ACTION_SIM_STATE_CHANGED:
815                 // Avoid rebroadcast because SysUI is direct boot aware.
816                 if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
817                     break;
818                 }
819                 // Might have different subscriptions now.
820                 updateMobileControllers();
821                 break;
822             case Intent.ACTION_SERVICE_STATE:
823                 mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
824                 if (mMobileSignalControllers.size() == 0) {
825                     // If none of the subscriptions are active, we might need to recalculate
826                     // emergency state.
827                     recalculateEmergency();
828                 }
829                 break;
830             case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
831                 mConfig = Config.readConfig(mContext);
832                 mReceiverHandler.post(this::handleConfigurationChanged);
833                 break;
834             case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
835                 mMainHandler.post(() -> mInternetDialogManager.create(true,
836                         mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi(),
837                         null /* view */));
838                 break;
839             default:
840                 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
841                         INVALID_SUBSCRIPTION_ID);
842                 if (SubscriptionManager.isValidSubscriptionId(subId)) {
843                     if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
844                         mMobileSignalControllers.get(subId).handleBroadcast(intent);
845                     } else {
846                         // Can't find this subscription...  We must be out of date.
847                         updateMobileControllers();
848                     }
849                 } else {
850                     // No sub id, must be for the wifi.
851                     mWifiSignalController.handleBroadcast(intent);
852                 }
853                 break;
854         }
855     }
856 
857     @VisibleForTesting
handleConfigurationChanged()858     void handleConfigurationChanged() {
859         updateMobileControllers();
860         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
861             MobileSignalController controller = mMobileSignalControllers.valueAt(i);
862             controller.setConfiguration(mConfig);
863         }
864         refreshLocale();
865     }
866 
updateMobileControllers()867     private void updateMobileControllers() {
868         if (!mListening) {
869             return;
870         }
871         doUpdateMobileControllers();
872     }
873 
filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions)874     private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
875         if (subscriptions.size() == 2) {
876             SubscriptionInfo info1 = subscriptions.get(0);
877             SubscriptionInfo info2 = subscriptions.get(1);
878             if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
879                 // If both subscriptions are primary, show both.
880                 if (!info1.isOpportunistic() && !info2.isOpportunistic()) return;
881 
882                 // If carrier required, always show signal bar of primary subscription.
883                 // Otherwise, show whichever subscription is currently active for Internet.
884                 boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig()
885                         .getBoolean(CarrierConfigManager
886                         .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN);
887                 if (alwaysShowPrimary) {
888                     subscriptions.remove(info1.isOpportunistic() ? info1 : info2);
889                 } else {
890                     subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription
891                             ? info2 : info1);
892                 }
893             }
894         }
895     }
896 
897     @VisibleForTesting
doUpdateMobileControllers()898     void doUpdateMobileControllers() {
899         List<SubscriptionInfo> subscriptions = mSubscriptionManager
900                 .getCompleteActiveSubscriptionInfoList();
901         if (subscriptions == null) {
902             subscriptions = Collections.emptyList();
903         }
904 
905         filterMobileSubscriptionInSameGroup(subscriptions);
906 
907         // If there have been no relevant changes to any of the subscriptions, we can leave as is.
908         if (hasCorrectMobileControllers(subscriptions)) {
909             // Even if the controllers are correct, make sure we have the right no sims state.
910             // Such as on boot, don't need any controllers, because there are no sims,
911             // but we still need to update the no sim state.
912             updateNoSims();
913             return;
914         }
915         synchronized (mLock) {
916             setCurrentSubscriptionsLocked(subscriptions);
917         }
918         updateNoSims();
919         recalculateEmergency();
920     }
921 
922     @VisibleForTesting
updateNoSims()923     protected void updateNoSims() {
924         boolean hasNoSubs = mHasMobileDataFeature && mMobileSignalControllers.size() == 0;
925         boolean simDetected = hasAnySim();
926         if (hasNoSubs != mHasNoSubs || simDetected != mSimDetected) {
927             mHasNoSubs = hasNoSubs;
928             mSimDetected = simDetected;
929             mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
930         }
931     }
932 
hasAnySim()933     private boolean hasAnySim() {
934         int simCount = mPhone.getActiveModemCount();
935         for (int i = 0; i < simCount; i++) {
936             int state = mPhone.getSimState(i);
937             if (state != TelephonyManager.SIM_STATE_ABSENT
938                     && state != TelephonyManager.SIM_STATE_UNKNOWN) {
939                 return true;
940             }
941         }
942         return false;
943     }
944 
945     @GuardedBy("mLock")
946     @VisibleForTesting
setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions)947     void setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions) {
948         Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() {
949             @Override
950             public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) {
951                 return lhs.getSimSlotIndex() == rhs.getSimSlotIndex()
952                         ? lhs.getSubscriptionId() - rhs.getSubscriptionId()
953                         : lhs.getSimSlotIndex() - rhs.getSimSlotIndex();
954             }
955         });
956         Log.i(
957                 TAG,
958                 String.format(
959                         Locale.US,
960                         "Subscriptions changed: %s",
961                         createSubscriptionChangeStatement(mCurrentSubscriptions, subscriptions)));
962         mCurrentSubscriptions = subscriptions;
963 
964         SparseArray<MobileSignalController> cachedControllers =
965                 new SparseArray<MobileSignalController>();
966         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
967             cachedControllers.put(mMobileSignalControllers.keyAt(i),
968                     mMobileSignalControllers.valueAt(i));
969         }
970         mMobileSignalControllers.clear();
971         final int num = subscriptions.size();
972         for (int i = 0; i < num; i++) {
973             int subId = subscriptions.get(i).getSubscriptionId();
974             // If we have a copy of this controller already reuse it, otherwise make a new one.
975             if (cachedControllers.indexOfKey(subId) >= 0) {
976                 mMobileSignalControllers.put(subId, cachedControllers.get(subId));
977                 cachedControllers.remove(subId);
978             } else {
979                 MobileSignalController controller = mMobileFactory.createMobileSignalController(
980                         mConfig,
981                         mHasMobileDataFeature,
982                         mPhone.createForSubscriptionId(subId),
983                         this,
984                         subscriptions.get(i),
985                         mSubDefaults,
986                         mReceiverHandler.getLooper()
987                 );
988                 controller.setUserSetupComplete(mUserSetup);
989                 mMobileSignalControllers.put(subId, controller);
990                 if (subscriptions.get(i).getSimSlotIndex() == 0) {
991                     mDefaultSignalController = controller;
992                 }
993                 if (mListening) {
994                     controller.registerListener();
995                 }
996             }
997         }
998         if (mListening) {
999             for (int i = 0; i < cachedControllers.size(); i++) {
1000                 int key = cachedControllers.keyAt(i);
1001                 if (cachedControllers.get(key) == mDefaultSignalController) {
1002                     mDefaultSignalController = null;
1003                 }
1004                 cachedControllers.get(key).unregisterListener();
1005             }
1006         }
1007         mCallbackHandler.setSubs(subscriptions);
1008         notifyAllListeners();
1009 
1010         // There may be new MobileSignalControllers around, make sure they get the current
1011         // inet condition and airplane mode.
1012         pushConnectivityToSignals();
1013         updateAirplaneMode(true /* force */);
1014     }
1015 
setUserSetupComplete(final boolean userSetup)1016     private void setUserSetupComplete(final boolean userSetup) {
1017         mReceiverHandler.post(() -> handleSetUserSetupComplete(userSetup));
1018     }
1019 
handleSetUserSetupComplete(boolean userSetup)1020     private void handleSetUserSetupComplete(boolean userSetup) {
1021         mUserSetup = userSetup;
1022         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1023             MobileSignalController controller = mMobileSignalControllers.valueAt(i);
1024             controller.setUserSetupComplete(mUserSetup);
1025         }
1026     }
1027 
1028     @VisibleForTesting
isUserSetup()1029     boolean isUserSetup() {
1030         return mUserSetup;
1031     }
1032 
1033     @VisibleForTesting
hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions)1034     boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) {
1035         if (allSubscriptions.size() != mMobileSignalControllers.size()) {
1036             return false;
1037         }
1038         for (SubscriptionInfo info : allSubscriptions) {
1039             if (mMobileSignalControllers.indexOfKey(info.getSubscriptionId()) < 0) {
1040                 return false;
1041             }
1042         }
1043         return true;
1044     }
1045 
1046     @VisibleForTesting
setNoNetworksAvailable(boolean noNetworksAvailable)1047     void setNoNetworksAvailable(boolean noNetworksAvailable) {
1048         mNoNetworksAvailable = noNetworksAvailable;
1049     }
1050 
updateAirplaneMode(boolean force)1051     private void updateAirplaneMode(boolean force) {
1052         boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
1053                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
1054         if (airplaneMode != mAirplaneMode || force) {
1055             mAirplaneMode = airplaneMode;
1056             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1057                 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
1058                 mobileSignalController.setAirplaneMode(mAirplaneMode);
1059             }
1060             notifyListeners();
1061         }
1062     }
1063 
refreshLocale()1064     private void refreshLocale() {
1065         Locale current = mContext.getResources().getConfiguration().locale;
1066         if (!current.equals(mLocale)) {
1067             mLocale = current;
1068             mWifiSignalController.refreshLocale();
1069             notifyAllListeners();
1070         }
1071     }
1072 
1073     /**
1074      * Forces update of all callbacks on both SignalClusters and
1075      * NetworkSignalChangedCallbacks.
1076      */
notifyAllListeners()1077     private void notifyAllListeners() {
1078         notifyListeners();
1079         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1080             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
1081             mobileSignalController.notifyListeners();
1082         }
1083         mWifiSignalController.notifyListeners();
1084         mEthernetSignalController.notifyListeners();
1085     }
1086 
1087     /**
1088      * Notifies listeners of changes in state of to the NetworkController, but
1089      * does not notify for any info on SignalControllers, for that call
1090      * notifyAllListeners.
1091      */
notifyListeners()1092     private void notifyListeners() {
1093         mCallbackHandler.setIsAirplaneMode(
1094                 new IconState(
1095                         mAirplaneMode,
1096                         TelephonyIcons.FLIGHT_MODE_ICON,
1097                         mContext.getString(R.string.accessibility_airplane_mode)));
1098         mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
1099     }
1100 
1101     /**
1102      * Update the Inet conditions and what network we are connected to.
1103      */
updateConnectivity()1104     private void updateConnectivity() {
1105         mConnectedTransports.clear();
1106         mValidatedTransports.clear();
1107         if (mLastDefaultNetworkCapabilities != null) {
1108             for (int transportType : mLastDefaultNetworkCapabilities.getTransportTypes()) {
1109                 if (transportType != NetworkCapabilities.TRANSPORT_CELLULAR
1110                         && transportType != NetworkCapabilities.TRANSPORT_WIFI
1111                         && transportType != NetworkCapabilities.TRANSPORT_ETHERNET) {
1112                     continue;
1113                 }
1114                 if (transportType == NetworkCapabilities.TRANSPORT_CELLULAR
1115                         && Utils.tryGetWifiInfoForVcn(mLastDefaultNetworkCapabilities) != null) {
1116                     mConnectedTransports.set(NetworkCapabilities.TRANSPORT_WIFI);
1117                     if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
1118                         mValidatedTransports.set(NetworkCapabilities.TRANSPORT_WIFI);
1119                     }
1120                 } else {
1121                     mConnectedTransports.set(transportType);
1122                     if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
1123                         mValidatedTransports.set(transportType);
1124                     }
1125                 }
1126             }
1127         }
1128 
1129         if (mForceCellularValidated) mValidatedTransports.set(TRANSPORT_CELLULAR);
1130 
1131         if (CHATTY) {
1132             Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports);
1133             Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
1134         }
1135 
1136         mInetCondition = mValidatedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
1137                 || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
1138                 || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
1139 
1140         pushConnectivityToSignals();
1141         mNoDefaultNetwork = !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
1142                 && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
1143                 && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
1144         mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition,
1145                 mNoNetworksAvailable);
1146     }
1147 
1148     /**
1149      * Pushes the current connectivity state to all SignalControllers.
1150      */
pushConnectivityToSignals()1151     private void pushConnectivityToSignals() {
1152         // We want to update all the icons, all at once, for any condition change
1153         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1154             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
1155             mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
1156         }
1157         mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
1158         mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
1159     }
1160 
1161     /** */
1162     @NeverCompile
dump(PrintWriter pw, String[] args)1163     public void dump(PrintWriter pw, String[] args) {
1164         pw.println("NetworkController state:");
1165         pw.println("  mUserSetup=" + mUserSetup);
1166 
1167         pw.println("  - telephony ------");
1168         pw.print("  hasVoiceCallingFeature()=");
1169         pw.println(hasVoiceCallingFeature());
1170         pw.println("  mListening=" + mListening);
1171         pw.println("  mActiveMobileDataSubscription=" + mActiveMobileDataSubscription);
1172 
1173         pw.println("  - connectivity ------");
1174         pw.print("  mConnectedTransports=");
1175         pw.println(mConnectedTransports);
1176         pw.print("  mValidatedTransports=");
1177         pw.println(mValidatedTransports);
1178         pw.print("  mInetCondition=");
1179         pw.println(mInetCondition);
1180         pw.print("  mAirplaneMode=");
1181         pw.println(mAirplaneMode);
1182         pw.print("  mLocale=");
1183         pw.println(mLocale);
1184         pw.print("  mLastServiceState=");
1185         pw.println(mLastServiceState);
1186         pw.print("  mIsEmergency=");
1187         pw.println(mIsEmergency);
1188         pw.print("  mEmergencySource=");
1189         pw.println(emergencyToString(mEmergencySource));
1190 
1191         pw.println("  - DefaultNetworkCallback -----");
1192         int size = 0;
1193         for (int i = 0; i < HISTORY_SIZE; i++) {
1194             if (mHistory[i] != null) {
1195                 size++;
1196             }
1197         }
1198         for (int i = mHistoryIndex + HISTORY_SIZE - 1;
1199                 i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
1200             pw.println("  Previous NetworkCallback(" + (mHistoryIndex + HISTORY_SIZE - i) + "): "
1201                     + mHistory[i & (HISTORY_SIZE - 1)]);
1202         }
1203 
1204         pw.println("  - config ------");
1205         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1206             MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
1207             mobileSignalController.dump(pw);
1208         }
1209         mWifiSignalController.dump(pw);
1210 
1211         mEthernetSignalController.dump(pw);
1212 
1213         mAccessPoints.dump(pw);
1214 
1215         mCallbackHandler.dump(pw);
1216     }
1217 
emergencyToString(int emergencySource)1218     private static String emergencyToString(int emergencySource) {
1219         if (emergencySource > EMERGENCY_NO_SUB) {
1220             return "ASSUMED_VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER)
1221                     + ")";
1222         } else if (emergencySource > EMERGENCY_NO_SUB) {
1223             return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")";
1224         } else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) {
1225             return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")";
1226         } else if (emergencySource > EMERGENCY_FIRST_CONTROLLER) {
1227             return "FIRST_CONTROLLER(" + (emergencySource - EMERGENCY_FIRST_CONTROLLER) + ")";
1228         } else if (emergencySource == EMERGENCY_NO_CONTROLLERS) {
1229             return "NO_CONTROLLERS";
1230         }
1231         return "UNKNOWN_SOURCE";
1232     }
1233 
1234     private boolean mDemoInetCondition;
1235 
1236     @Override
onDemoModeStarted()1237     public void onDemoModeStarted() {
1238         if (DEBUG) Log.d(TAG, "Entering demo mode");
1239         unregisterListeners();
1240         mDemoInetCondition = mInetCondition;
1241     }
1242 
1243     @Override
onDemoModeFinished()1244     public void onDemoModeFinished() {
1245         if (DEBUG) Log.d(TAG, "Exiting demo mode");
1246         // Update what MobileSignalControllers, because they may change
1247         // to set the number of sim slots.
1248         updateMobileControllers();
1249         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1250             MobileSignalController controller = mMobileSignalControllers.valueAt(i);
1251             controller.resetLastState();
1252         }
1253         mWifiSignalController.resetLastState();
1254         mReceiverHandler.post(mRegisterListeners);
1255         notifyAllListeners();
1256     }
1257 
1258     @Override
dispatchDemoCommand(String command, Bundle args)1259     public void dispatchDemoCommand(String command, Bundle args) {
1260         if (!mDemoModeController.isInDemoMode()) {
1261             return;
1262         }
1263 
1264         String airplane = args.getString("airplane");
1265         if (airplane != null) {
1266             boolean show = airplane.equals("show");
1267             mCallbackHandler.setIsAirplaneMode(
1268                     new IconState(
1269                             show,
1270                             TelephonyIcons.FLIGHT_MODE_ICON,
1271                             mContext.getString(R.string.accessibility_airplane_mode)));
1272         }
1273         String fully = args.getString("fully");
1274         if (fully != null) {
1275             mDemoInetCondition = Boolean.parseBoolean(fully);
1276             BitSet connected = new BitSet();
1277 
1278             if (mDemoInetCondition) {
1279                 connected.set(mWifiSignalController.mTransportType);
1280             }
1281             mWifiSignalController.updateConnectivity(connected, connected);
1282             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1283                 MobileSignalController controller = mMobileSignalControllers.valueAt(i);
1284                 if (mDemoInetCondition) {
1285                     connected.set(controller.mTransportType);
1286                 }
1287                 controller.updateConnectivity(connected, connected);
1288             }
1289         }
1290         String sims = args.getString("sims");
1291         if (sims != null) {
1292             int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8);
1293             List<SubscriptionInfo> subs = new ArrayList<>();
1294             if (num != mMobileSignalControllers.size()) {
1295                 mMobileSignalControllers.clear();
1296                 int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
1297                 for (int i = start /* get out of normal index range */; i < start + num; i++) {
1298                     subs.add(addDemoModeSignalController(i, i));
1299                 }
1300                 mCallbackHandler.setSubs(subs);
1301                 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1302                     int key = mMobileSignalControllers.keyAt(i);
1303                     MobileSignalController controller = mMobileSignalControllers.get(key);
1304                     controller.notifyListeners();
1305                 }
1306             }
1307         }
1308         String nosim = args.getString("nosim");
1309         if (nosim != null) {
1310             mHasNoSubs = nosim.equals("show");
1311             mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
1312         }
1313         String mobile = args.getString("mobile");
1314         if (mobile != null) {
1315             boolean show = mobile.equals("show");
1316             String datatype = args.getString("datatype");
1317             String slotString = args.getString("slot");
1318             int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString);
1319             slot = MathUtils.constrain(slot, 0, 8);
1320             String carrierIdString = args.getString("carrierid");
1321             int carrierId = TextUtils.isEmpty(carrierIdString) ? 0
1322                     : Integer.parseInt(carrierIdString);
1323             // Ensure we have enough sim slots
1324             // TODO(b/336357360): This is the origination of the infinite loop bug, for those
1325             // following along at home.
1326             List<SubscriptionInfo> subs = new ArrayList<>();
1327             while (mMobileSignalControllers.size() <= slot) {
1328                 int nextSlot = mMobileSignalControllers.size();
1329                 subs.add(addDemoModeSignalController(nextSlot, nextSlot));
1330             }
1331             if (!subs.isEmpty()) {
1332                 mCallbackHandler.setSubs(subs);
1333             }
1334             // Hack to index linearly for easy use.
1335             MobileSignalController controller = mMobileSignalControllers.valueAt(slot);
1336             if (carrierId != 0) {
1337                 controller.getState().setCarrierId(carrierId);
1338             }
1339             controller.getState().dataSim = datatype != null;
1340             controller.getState().isDefault = datatype != null;
1341             controller.getState().dataConnected = datatype != null;
1342             if (datatype != null) {
1343                 controller.getState().iconGroup =
1344                         datatype.equals("1x") ? TelephonyIcons.ONE_X :
1345                         datatype.equals("3g") ? TelephonyIcons.THREE_G :
1346                         datatype.equals("4g") ? TelephonyIcons.FOUR_G :
1347                         datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS :
1348                         datatype.equals("5g") ? TelephonyIcons.NR_5G :
1349                         datatype.equals("5ge") ? TelephonyIcons.LTE_CA_5G_E :
1350                         datatype.equals("5g+") ? TelephonyIcons.NR_5G_PLUS :
1351                         datatype.equals("e") ? TelephonyIcons.E :
1352                         datatype.equals("g") ? TelephonyIcons.G :
1353                         datatype.equals("h") ? TelephonyIcons.H :
1354                         datatype.equals("h+") ? TelephonyIcons.H_PLUS :
1355                         datatype.equals("lte") ? TelephonyIcons.LTE :
1356                         datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS :
1357                         datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED :
1358                         datatype.equals("not") ? TelephonyIcons.NOT_DEFAULT_DATA :
1359                         TelephonyIcons.UNKNOWN;
1360             }
1361             if (args.containsKey("roam")) {
1362                 controller.getState().roaming = "show".equals(args.getString("roam"));
1363             }
1364             String level = args.getString("level");
1365             if (level != null) {
1366                 controller.getState().level = level.equals("null") ? -1
1367                         : Math.min(Integer.parseInt(level),
1368                                 CellSignalStrength.getNumSignalStrengthLevels());
1369                 controller.getState().connected = controller.getState().level >= 0;
1370             }
1371             if (args.containsKey("inflate")) {
1372                 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1373                     mMobileSignalControllers.valueAt(i).mInflateSignalStrengths =
1374                             "true".equals(args.getString("inflate"));
1375                 }
1376             }
1377             String activity = args.getString("activity");
1378             if (activity != null) {
1379                 controller.getState().dataConnected = true;
1380                 switch (activity) {
1381                     case "inout":
1382                         controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
1383                         break;
1384                     case "in":
1385                         controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN);
1386                         break;
1387                     case "out":
1388                         controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT);
1389                         break;
1390                     default:
1391                         controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
1392                         break;
1393                 }
1394             } else {
1395                 controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
1396             }
1397             controller.getState().enabled = show;
1398             controller.notifyListeners();
1399         }
1400         String carrierNetworkChange = args.getString("carriernetworkchange");
1401         if (carrierNetworkChange != null) {
1402             boolean show = carrierNetworkChange.equals("show");
1403             for (int i = 0; i < mMobileSignalControllers.size(); i++) {
1404                 MobileSignalController controller = mMobileSignalControllers.valueAt(i);
1405                 controller.setCarrierNetworkChangeMode(show);
1406             }
1407         }
1408     }
1409 
1410     @Override
demoCommands()1411     public List<String> demoCommands() {
1412         List<String> s = new ArrayList<>();
1413         s.add(DemoMode.COMMAND_NETWORK);
1414         return s;
1415     }
1416 
recordLastNetworkCallback(String callback)1417     private void recordLastNetworkCallback(String callback) {
1418         mHistory[mHistoryIndex] = callback;
1419         mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
1420     }
1421 
addDemoModeSignalController(int id, int simSlotIndex)1422     private SubscriptionInfo addDemoModeSignalController(int id, int simSlotIndex) {
1423         SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
1424                 null, null, null, "", false, null, null);
1425 
1426         MobileSignalController controller = mMobileFactory.createMobileSignalController(
1427                 mConfig,
1428                 mHasMobileDataFeature,
1429                 mPhone.createForSubscriptionId(info.getSubscriptionId()),
1430                 this,
1431                 info,
1432                 mSubDefaults,
1433                 mReceiverHandler.getLooper()
1434         );
1435 
1436         mMobileSignalControllers.put(id, controller);
1437         controller.getState().userSetup = true;
1438         return info;
1439     }
1440 
1441     /** */
isRadioOn()1442     public boolean isRadioOn() {
1443         return !mAirplaneMode;
1444     }
1445 
1446     private class SubListener extends OnSubscriptionsChangedListener {
SubListener(Looper looper)1447         SubListener(Looper looper) {
1448             super(looper);
1449         }
1450 
1451         @Override
onSubscriptionsChanged()1452         public void onSubscriptionsChanged() {
1453             updateMobileControllers();
1454         }
1455     }
1456 
1457     /**
1458      * Used to register listeners from the BG Looper, this way the PhoneStateListeners that
1459      * get created will also run on the BG Looper.
1460      */
1461     private final Runnable mRegisterListeners = () -> registerListeners();
1462 
1463     /** 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)1464     private static String createSubscriptionChangeStatement(
1465             final @Nullable List<SubscriptionInfo> oldSubscriptions,
1466             final @Nullable List<SubscriptionInfo> newSubscriptions) {
1467         return String.format(
1468                 Locale.US,
1469                 "old=%s, new=%s",
1470                 toSubscriptionIds(oldSubscriptions),
1471                 toSubscriptionIds(newSubscriptions));
1472     }
1473 
1474     /** Returns to a list of subscription IDs for the given list of {@link SubscriptionInfo} */
1475     @Nullable
toSubscriptionIds( final @Nullable List<SubscriptionInfo> subscriptions)1476     private static List<Integer> toSubscriptionIds(
1477             final @Nullable List<SubscriptionInfo> subscriptions) {
1478         return subscriptions != null ? subscriptions.stream().map(
1479                 SubscriptionInfo::getSubscriptionId).collect(Collectors.toList()) : null;
1480     }
1481 }
1482