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