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