• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.policy;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.res.Resources;
24 import android.net.ConnectivityManager;
25 import android.net.NetworkCapabilities;
26 import android.net.wifi.WifiManager;
27 import android.os.AsyncTask;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.os.Looper;
31 import android.provider.Settings;
32 import android.telephony.ServiceState;
33 import android.telephony.SubscriptionInfo;
34 import android.telephony.SubscriptionManager;
35 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
36 import android.telephony.TelephonyManager;
37 import android.text.TextUtils;
38 import android.util.Log;
39 import android.util.MathUtils;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.internal.telephony.PhoneConstants;
43 import com.android.internal.telephony.TelephonyIntents;
44 import com.android.settingslib.net.DataUsageController;
45 import com.android.systemui.DemoMode;
46 import com.android.systemui.R;
47 
48 import java.io.FileDescriptor;
49 import java.io.PrintWriter;
50 import java.util.ArrayList;
51 import java.util.BitSet;
52 import java.util.Collections;
53 import java.util.Comparator;
54 import java.util.HashMap;
55 import java.util.List;
56 import java.util.Locale;
57 import java.util.Map;
58 
59 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
60 
61 /** Platform implementation of the network controller. **/
62 public class NetworkControllerImpl extends BroadcastReceiver
63         implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider {
64     // debug
65     static final String TAG = "NetworkController";
66     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
67     // additional diagnostics, but not logspew
68     static final boolean CHATTY =  Log.isLoggable(TAG + "Chat", Log.DEBUG);
69 
70     private static final int EMERGENCY_NO_CONTROLLERS = 0;
71     private static final int EMERGENCY_FIRST_CONTROLLER = 100;
72     private static final int EMERGENCY_VOICE_CONTROLLER = 200;
73     private static final int EMERGENCY_NO_SUB = 300;
74 
75     private final Context mContext;
76     private final TelephonyManager mPhone;
77     private final WifiManager mWifiManager;
78     private final ConnectivityManager mConnectivityManager;
79     private final SubscriptionManager mSubscriptionManager;
80     private final boolean mHasMobileDataFeature;
81     private final SubscriptionDefaults mSubDefaults;
82     private final DataSaverController mDataSaverController;
83     private Config mConfig;
84 
85     // Subcontrollers.
86     @VisibleForTesting
87     final WifiSignalController mWifiSignalController;
88 
89     @VisibleForTesting
90     final EthernetSignalController mEthernetSignalController;
91 
92     @VisibleForTesting
93     final Map<Integer, MobileSignalController> mMobileSignalControllers =
94             new HashMap<Integer, MobileSignalController>();
95     // When no SIMs are around at setup, and one is added later, it seems to default to the first
96     // SIM for most actions.  This may be null if there aren't any SIMs around.
97     private MobileSignalController mDefaultSignalController;
98     private final AccessPointControllerImpl mAccessPoints;
99     private final DataUsageController mDataUsageController;
100 
101     private boolean mInetCondition; // Used for Logging and demo.
102 
103     // BitSets indicating which network transport types (e.g., TRANSPORT_WIFI, TRANSPORT_MOBILE) are
104     // connected and validated, respectively.
105     private final BitSet mConnectedTransports = new BitSet();
106     private final BitSet mValidatedTransports = new BitSet();
107 
108     // States that don't belong to a subcontroller.
109     private boolean mAirplaneMode = false;
110     private boolean mHasNoSims;
111     private Locale mLocale = null;
112     // This list holds our ordering.
113     private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>();
114 
115     @VisibleForTesting
116     boolean mListening;
117 
118     // The current user ID.
119     private int mCurrentUserId;
120 
121     private OnSubscriptionsChangedListener mSubscriptionListener;
122 
123     // Handler that all broadcasts are received on.
124     private final Handler mReceiverHandler;
125     // Handler that all callbacks are made on.
126     private final CallbackHandler mCallbackHandler;
127 
128     private int mEmergencySource;
129     private boolean mIsEmergency;
130 
131     @VisibleForTesting
132     ServiceState mLastServiceState;
133     private boolean mUserSetup;
134 
135     /**
136      * Construct this controller object and register for updates.
137      */
NetworkControllerImpl(Context context, Looper bgLooper)138     public NetworkControllerImpl(Context context, Looper bgLooper) {
139         this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
140                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
141                 (WifiManager) context.getSystemService(Context.WIFI_SERVICE),
142                 SubscriptionManager.from(context), Config.readConfig(context), bgLooper,
143                 new CallbackHandler(),
144                 new AccessPointControllerImpl(context, bgLooper),
145                 new DataUsageController(context),
146                 new SubscriptionDefaults());
147         mReceiverHandler.post(mRegisterListeners);
148     }
149 
150     @VisibleForTesting
NetworkControllerImpl(Context context, ConnectivityManager connectivityManager, TelephonyManager telephonyManager, WifiManager wifiManager, SubscriptionManager subManager, Config config, Looper bgLooper, CallbackHandler callbackHandler, AccessPointControllerImpl accessPointController, DataUsageController dataUsageController, SubscriptionDefaults defaultsHandler)151     NetworkControllerImpl(Context context, ConnectivityManager connectivityManager,
152             TelephonyManager telephonyManager, WifiManager wifiManager,
153             SubscriptionManager subManager, Config config, Looper bgLooper,
154             CallbackHandler callbackHandler,
155             AccessPointControllerImpl accessPointController,
156             DataUsageController dataUsageController,
157             SubscriptionDefaults defaultsHandler) {
158         mContext = context;
159         mConfig = config;
160         mReceiverHandler = new Handler(bgLooper);
161         mCallbackHandler = callbackHandler;
162         mDataSaverController = new DataSaverController(context);
163 
164         mSubscriptionManager = subManager;
165         mSubDefaults = defaultsHandler;
166         mConnectivityManager = connectivityManager;
167         mHasMobileDataFeature =
168                 mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
169 
170         // telephony
171         mPhone = telephonyManager;
172 
173         // wifi
174         mWifiManager = wifiManager;
175 
176         mLocale = mContext.getResources().getConfiguration().locale;
177         mAccessPoints = accessPointController;
178         mDataUsageController = dataUsageController;
179         mDataUsageController.setNetworkController(this);
180         // TODO: Find a way to move this into DataUsageController.
181         mDataUsageController.setCallback(new DataUsageController.Callback() {
182             @Override
183             public void onMobileDataEnabled(boolean enabled) {
184                 mCallbackHandler.setMobileDataEnabled(enabled);
185             }
186         });
187         mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
188                 mCallbackHandler, this);
189 
190         mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this);
191 
192         // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
193         updateAirplaneMode(true /* force callback */);
194     }
195 
getDataSaverController()196     public DataSaverController getDataSaverController() {
197         return mDataSaverController;
198     }
199 
registerListeners()200     private void registerListeners() {
201         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
202             mobileSignalController.registerListener();
203         }
204         if (mSubscriptionListener == null) {
205             mSubscriptionListener = new SubListener();
206         }
207         mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
208 
209         // broadcasts
210         IntentFilter filter = new IntentFilter();
211         filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
212         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
213         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
214         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
215         filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
216         filter.addAction(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
217         filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
218         filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
219         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
220         filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
221         filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
222         mContext.registerReceiver(this, filter, null, mReceiverHandler);
223         mListening = true;
224 
225         updateMobileControllers();
226     }
227 
unregisterListeners()228     private void unregisterListeners() {
229         mListening = false;
230         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
231             mobileSignalController.unregisterListener();
232         }
233         mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener);
234         mContext.unregisterReceiver(this);
235     }
236 
getConnectedWifiLevel()237     public int getConnectedWifiLevel() {
238         return mWifiSignalController.getState().level;
239     }
240 
241     @Override
getAccessPointController()242     public AccessPointController getAccessPointController() {
243         return mAccessPoints;
244     }
245 
246     @Override
getMobileDataController()247     public DataUsageController getMobileDataController() {
248         return mDataUsageController;
249     }
250 
addEmergencyListener(EmergencyListener listener)251     public void addEmergencyListener(EmergencyListener listener) {
252         mCallbackHandler.setListening(listener, true);
253         mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
254     }
255 
removeEmergencyListener(EmergencyListener listener)256     public void removeEmergencyListener(EmergencyListener listener) {
257         mCallbackHandler.setListening(listener, false);
258     }
259 
hasMobileDataFeature()260     public boolean hasMobileDataFeature() {
261         return mHasMobileDataFeature;
262     }
263 
hasVoiceCallingFeature()264     public boolean hasVoiceCallingFeature() {
265         return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
266     }
267 
getDataController()268     private MobileSignalController getDataController() {
269         int dataSubId = mSubDefaults.getDefaultDataSubId();
270         if (!SubscriptionManager.isValidSubscriptionId(dataSubId)) {
271             if (DEBUG) Log.e(TAG, "No data sim selected");
272             return mDefaultSignalController;
273         }
274         if (mMobileSignalControllers.containsKey(dataSubId)) {
275             return mMobileSignalControllers.get(dataSubId);
276         }
277         if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + dataSubId);
278         return mDefaultSignalController;
279     }
280 
getMobileDataNetworkName()281     public String getMobileDataNetworkName() {
282         MobileSignalController controller = getDataController();
283         return controller != null ? controller.getState().networkNameData : "";
284     }
285 
isEmergencyOnly()286     public boolean isEmergencyOnly() {
287         if (mMobileSignalControllers.size() == 0) {
288             // When there are no active subscriptions, determine emengency state from last
289             // broadcast.
290             mEmergencySource = EMERGENCY_NO_CONTROLLERS;
291             return mLastServiceState != null && mLastServiceState.isEmergencyOnly();
292         }
293         int voiceSubId = mSubDefaults.getDefaultVoiceSubId();
294         if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) {
295             for (MobileSignalController mobileSignalController :
296                                             mMobileSignalControllers.values()) {
297                 if (!mobileSignalController.getState().isEmergency) {
298                     mEmergencySource = EMERGENCY_FIRST_CONTROLLER
299                             + mobileSignalController.mSubscriptionInfo.getSubscriptionId();
300                     if (DEBUG) Log.d(TAG, "Found emergency " + mobileSignalController.mTag);
301                     return false;
302                 }
303             }
304         }
305         if (mMobileSignalControllers.containsKey(voiceSubId)) {
306             mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId;
307             if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId);
308             return mMobileSignalControllers.get(voiceSubId).getState().isEmergency;
309         }
310         if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
311         mEmergencySource = EMERGENCY_NO_SUB + voiceSubId;
312         // Something is wrong, better assume we can't make calls...
313         return true;
314     }
315 
316     /**
317      * Emergency status may have changed (triggered by MobileSignalController),
318      * so we should recheck and send out the state to listeners.
319      */
recalculateEmergency()320     void recalculateEmergency() {
321         mIsEmergency = isEmergencyOnly();
322         mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
323     }
324 
addSignalCallback(SignalCallback cb)325     public void addSignalCallback(SignalCallback cb) {
326         cb.setSubs(mCurrentSubscriptions);
327         cb.setIsAirplaneMode(new IconState(mAirplaneMode,
328                 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
329         cb.setNoSims(mHasNoSims);
330         mWifiSignalController.notifyListeners(cb);
331         mEthernetSignalController.notifyListeners(cb);
332         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
333             mobileSignalController.notifyListeners(cb);
334         }
335         mCallbackHandler.setListening(cb, true);
336     }
337 
338     @Override
removeSignalCallback(SignalCallback cb)339     public void removeSignalCallback(SignalCallback cb) {
340         mCallbackHandler.setListening(cb, false);
341     }
342 
343     @Override
setWifiEnabled(final boolean enabled)344     public void setWifiEnabled(final boolean enabled) {
345         new AsyncTask<Void, Void, Void>() {
346             @Override
347             protected Void doInBackground(Void... args) {
348                 // Disable tethering if enabling Wifi
349                 final int wifiApState = mWifiManager.getWifiApState();
350                 if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
351                         (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
352                     mWifiManager.setWifiApEnabled(null, false);
353                 }
354 
355                 mWifiManager.setWifiEnabled(enabled);
356                 return null;
357             }
358         }.execute();
359     }
360 
361     @Override
onUserSwitched(int newUserId)362     public void onUserSwitched(int newUserId) {
363         mCurrentUserId = newUserId;
364         mAccessPoints.onUserSwitched(newUserId);
365         updateConnectivity();
366     }
367 
368     @Override
onReceive(Context context, Intent intent)369     public void onReceive(Context context, Intent intent) {
370         if (CHATTY) {
371             Log.d(TAG, "onReceive: intent=" + intent);
372         }
373         final String action = intent.getAction();
374         if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
375                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
376             updateConnectivity();
377         } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
378             refreshLocale();
379             updateAirplaneMode(false);
380         } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED)) {
381             // We are using different subs now, we might be able to make calls.
382             recalculateEmergency();
383         } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
384             // Notify every MobileSignalController so they can know whether they are the
385             // data sim or not.
386             for (MobileSignalController controller : mMobileSignalControllers.values()) {
387                 controller.handleBroadcast(intent);
388             }
389         } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
390             // Might have different subscriptions now.
391             updateMobileControllers();
392         } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
393             mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
394             if (mMobileSignalControllers.size() == 0) {
395                 // If none of the subscriptions are active, we might need to recalculate
396                 // emergency state.
397                 recalculateEmergency();
398             }
399         } else {
400             int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
401                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
402             if (SubscriptionManager.isValidSubscriptionId(subId)) {
403                 if (mMobileSignalControllers.containsKey(subId)) {
404                     mMobileSignalControllers.get(subId).handleBroadcast(intent);
405                 } else {
406                     // Can't find this subscription...  We must be out of date.
407                     updateMobileControllers();
408                 }
409             } else {
410                 // No sub id, must be for the wifi.
411                 mWifiSignalController.handleBroadcast(intent);
412             }
413         }
414     }
415 
onConfigurationChanged()416     public void onConfigurationChanged() {
417         mConfig = Config.readConfig(mContext);
418         mReceiverHandler.post(new Runnable() {
419             @Override
420             public void run() {
421                 handleConfigurationChanged();
422             }
423         });
424     }
425 
426     @VisibleForTesting
handleConfigurationChanged()427     void handleConfigurationChanged() {
428         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
429             mobileSignalController.setConfiguration(mConfig);
430         }
431         refreshLocale();
432     }
433 
updateMobileControllers()434     private void updateMobileControllers() {
435         if (!mListening) {
436             return;
437         }
438         doUpdateMobileControllers();
439     }
440 
441     @VisibleForTesting
doUpdateMobileControllers()442     void doUpdateMobileControllers() {
443         List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList();
444         if (subscriptions == null) {
445             subscriptions = Collections.emptyList();
446         }
447         // If there have been no relevant changes to any of the subscriptions, we can leave as is.
448         if (hasCorrectMobileControllers(subscriptions)) {
449             // Even if the controllers are correct, make sure we have the right no sims state.
450             // Such as on boot, don't need any controllers, because there are no sims,
451             // but we still need to update the no sim state.
452             updateNoSims();
453             return;
454         }
455         setCurrentSubscriptions(subscriptions);
456         updateNoSims();
457         recalculateEmergency();
458     }
459 
460     @VisibleForTesting
updateNoSims()461     protected void updateNoSims() {
462         boolean hasNoSims = mHasMobileDataFeature && mMobileSignalControllers.size() == 0;
463         if (hasNoSims != mHasNoSims) {
464             mHasNoSims = hasNoSims;
465             mCallbackHandler.setNoSims(mHasNoSims);
466         }
467     }
468 
469     @VisibleForTesting
setCurrentSubscriptions(List<SubscriptionInfo> subscriptions)470     void setCurrentSubscriptions(List<SubscriptionInfo> subscriptions) {
471         Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() {
472             @Override
473             public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) {
474                 return lhs.getSimSlotIndex() == rhs.getSimSlotIndex()
475                         ? lhs.getSubscriptionId() - rhs.getSubscriptionId()
476                         : lhs.getSimSlotIndex() - rhs.getSimSlotIndex();
477             }
478         });
479         mCurrentSubscriptions = subscriptions;
480 
481         HashMap<Integer, MobileSignalController> cachedControllers =
482                 new HashMap<Integer, MobileSignalController>(mMobileSignalControllers);
483         mMobileSignalControllers.clear();
484         final int num = subscriptions.size();
485         for (int i = 0; i < num; i++) {
486             int subId = subscriptions.get(i).getSubscriptionId();
487             // If we have a copy of this controller already reuse it, otherwise make a new one.
488             if (cachedControllers.containsKey(subId)) {
489                 mMobileSignalControllers.put(subId, cachedControllers.remove(subId));
490             } else {
491                 MobileSignalController controller = new MobileSignalController(mContext, mConfig,
492                         mHasMobileDataFeature, mPhone, mCallbackHandler,
493                         this, subscriptions.get(i), mSubDefaults, mReceiverHandler.getLooper());
494                 controller.setUserSetupComplete(mUserSetup);
495                 mMobileSignalControllers.put(subId, controller);
496                 if (subscriptions.get(i).getSimSlotIndex() == 0) {
497                     mDefaultSignalController = controller;
498                 }
499                 if (mListening) {
500                     controller.registerListener();
501                 }
502             }
503         }
504         if (mListening) {
505             for (Integer key : cachedControllers.keySet()) {
506                 if (cachedControllers.get(key) == mDefaultSignalController) {
507                     mDefaultSignalController = null;
508                 }
509                 cachedControllers.get(key).unregisterListener();
510             }
511         }
512         mCallbackHandler.setSubs(subscriptions);
513         notifyAllListeners();
514 
515         // There may be new MobileSignalControllers around, make sure they get the current
516         // inet condition and airplane mode.
517         pushConnectivityToSignals();
518         updateAirplaneMode(true /* force */);
519     }
520 
setUserSetupComplete(final boolean userSetup)521     public void setUserSetupComplete(final boolean userSetup) {
522         mReceiverHandler.post(new Runnable() {
523             @Override
524             public void run() {
525                 handleSetUserSetupComplete(userSetup);
526             }
527         });
528     }
529 
530     @VisibleForTesting
handleSetUserSetupComplete(boolean userSetup)531     void handleSetUserSetupComplete(boolean userSetup) {
532         mUserSetup = userSetup;
533         for (MobileSignalController controller : mMobileSignalControllers.values()) {
534             controller.setUserSetupComplete(mUserSetup);
535         }
536     }
537 
538     @VisibleForTesting
hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions)539     boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) {
540         if (allSubscriptions.size() != mMobileSignalControllers.size()) {
541             return false;
542         }
543         for (SubscriptionInfo info : allSubscriptions) {
544             if (!mMobileSignalControllers.containsKey(info.getSubscriptionId())) {
545                 return false;
546             }
547         }
548         return true;
549     }
550 
updateAirplaneMode(boolean force)551     private void updateAirplaneMode(boolean force) {
552         boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
553                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
554         if (airplaneMode != mAirplaneMode || force) {
555             mAirplaneMode = airplaneMode;
556             for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
557                 mobileSignalController.setAirplaneMode(mAirplaneMode);
558             }
559             notifyListeners();
560         }
561     }
562 
refreshLocale()563     private void refreshLocale() {
564         Locale current = mContext.getResources().getConfiguration().locale;
565         if (!current.equals(mLocale)) {
566             mLocale = current;
567             notifyAllListeners();
568         }
569     }
570 
571     /**
572      * Forces update of all callbacks on both SignalClusters and
573      * NetworkSignalChangedCallbacks.
574      */
notifyAllListeners()575     private void notifyAllListeners() {
576         notifyListeners();
577         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
578             mobileSignalController.notifyListeners();
579         }
580         mWifiSignalController.notifyListeners();
581         mEthernetSignalController.notifyListeners();
582     }
583 
584     /**
585      * Notifies listeners of changes in state of to the NetworkController, but
586      * does not notify for any info on SignalControllers, for that call
587      * notifyAllListeners.
588      */
notifyListeners()589     private void notifyListeners() {
590         mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
591                 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
592         mCallbackHandler.setNoSims(mHasNoSims);
593     }
594 
595     /**
596      * Update the Inet conditions and what network we are connected to.
597      */
updateConnectivity()598     private void updateConnectivity() {
599         mConnectedTransports.clear();
600         mValidatedTransports.clear();
601         for (NetworkCapabilities nc :
602                 mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) {
603             for (int transportType : nc.getTransportTypes()) {
604                 mConnectedTransports.set(transportType);
605                 if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) {
606                     mValidatedTransports.set(transportType);
607                 }
608             }
609         }
610 
611         if (CHATTY) {
612             Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports);
613             Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
614         }
615 
616         mInetCondition = !mValidatedTransports.isEmpty();
617 
618         pushConnectivityToSignals();
619     }
620 
621     /**
622      * Pushes the current connectivity state to all SignalControllers.
623      */
pushConnectivityToSignals()624     private void pushConnectivityToSignals() {
625         // We want to update all the icons, all at once, for any condition change
626         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
627             mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
628         }
629         mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
630         mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
631     }
632 
dump(FileDescriptor fd, PrintWriter pw, String[] args)633     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
634         pw.println("NetworkController state:");
635 
636         pw.println("  - telephony ------");
637         pw.print("  hasVoiceCallingFeature()=");
638         pw.println(hasVoiceCallingFeature());
639 
640         pw.println("  - connectivity ------");
641         pw.print("  mConnectedTransports=");
642         pw.println(mConnectedTransports);
643         pw.print("  mValidatedTransports=");
644         pw.println(mValidatedTransports);
645         pw.print("  mInetCondition=");
646         pw.println(mInetCondition);
647         pw.print("  mAirplaneMode=");
648         pw.println(mAirplaneMode);
649         pw.print("  mLocale=");
650         pw.println(mLocale);
651         pw.print("  mLastServiceState=");
652         pw.println(mLastServiceState);
653         pw.print("  mIsEmergency=");
654         pw.println(mIsEmergency);
655         pw.print("  mEmergencySource=");
656         pw.println(emergencyToString(mEmergencySource));
657 
658         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
659             mobileSignalController.dump(pw);
660         }
661         mWifiSignalController.dump(pw);
662 
663         mEthernetSignalController.dump(pw);
664 
665         mAccessPoints.dump(pw);
666     }
667 
emergencyToString(int emergencySource)668     private static final String emergencyToString(int emergencySource) {
669         if (emergencySource > EMERGENCY_NO_SUB) {
670             return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")";
671         } else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) {
672             return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")";
673         } else if (emergencySource > EMERGENCY_FIRST_CONTROLLER) {
674             return "FIRST_CONTROLLER(" + (emergencySource - EMERGENCY_FIRST_CONTROLLER) + ")";
675         } else if (emergencySource == EMERGENCY_NO_CONTROLLERS) {
676             return "NO_CONTROLLERS";
677         }
678         return "UNKNOWN_SOURCE";
679     }
680 
681     private boolean mDemoMode;
682     private boolean mDemoInetCondition;
683     private WifiSignalController.WifiState mDemoWifiState;
684 
685     @Override
dispatchDemoCommand(String command, Bundle args)686     public void dispatchDemoCommand(String command, Bundle args) {
687         if (!mDemoMode && command.equals(COMMAND_ENTER)) {
688             if (DEBUG) Log.d(TAG, "Entering demo mode");
689             unregisterListeners();
690             mDemoMode = true;
691             mDemoInetCondition = mInetCondition;
692             mDemoWifiState = mWifiSignalController.getState();
693         } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
694             if (DEBUG) Log.d(TAG, "Exiting demo mode");
695             mDemoMode = false;
696             // Update what MobileSignalControllers, because they may change
697             // to set the number of sim slots.
698             updateMobileControllers();
699             for (MobileSignalController controller : mMobileSignalControllers.values()) {
700                 controller.resetLastState();
701             }
702             mWifiSignalController.resetLastState();
703             mReceiverHandler.post(mRegisterListeners);
704             notifyAllListeners();
705         } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
706             String airplane = args.getString("airplane");
707             if (airplane != null) {
708                 boolean show = airplane.equals("show");
709                 mCallbackHandler.setIsAirplaneMode(new IconState(show,
710                         TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode,
711                         mContext));
712             }
713             String fully = args.getString("fully");
714             if (fully != null) {
715                 mDemoInetCondition = Boolean.parseBoolean(fully);
716                 BitSet connected = new BitSet();
717 
718                 if (mDemoInetCondition) {
719                     connected.set(mWifiSignalController.mTransportType);
720                 }
721                 mWifiSignalController.updateConnectivity(connected, connected);
722                 for (MobileSignalController controller : mMobileSignalControllers.values()) {
723                     if (mDemoInetCondition) {
724                         connected.set(controller.mTransportType);
725                     }
726                     controller.updateConnectivity(connected, connected);
727                 }
728             }
729             String wifi = args.getString("wifi");
730             if (wifi != null) {
731                 boolean show = wifi.equals("show");
732                 String level = args.getString("level");
733                 if (level != null) {
734                     mDemoWifiState.level = level.equals("null") ? -1
735                             : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
736                     mDemoWifiState.connected = mDemoWifiState.level >= 0;
737                 }
738                 mDemoWifiState.enabled = show;
739                 mWifiSignalController.notifyListeners();
740             }
741             String sims = args.getString("sims");
742             if (sims != null) {
743                 int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8);
744                 List<SubscriptionInfo> subs = new ArrayList<>();
745                 if (num != mMobileSignalControllers.size()) {
746                     mMobileSignalControllers.clear();
747                     int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
748                     for (int i = start /* get out of normal index range */; i < start + num; i++) {
749                         subs.add(addSignalController(i, i));
750                     }
751                     mCallbackHandler.setSubs(subs);
752                 }
753             }
754             String nosim = args.getString("nosim");
755             if (nosim != null) {
756                 mHasNoSims = nosim.equals("show");
757                 mCallbackHandler.setNoSims(mHasNoSims);
758             }
759             String mobile = args.getString("mobile");
760             if (mobile != null) {
761                 boolean show = mobile.equals("show");
762                 String datatype = args.getString("datatype");
763                 String slotString = args.getString("slot");
764                 int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString);
765                 slot = MathUtils.constrain(slot, 0, 8);
766                 // Ensure we have enough sim slots
767                 List<SubscriptionInfo> subs = new ArrayList<>();
768                 while (mMobileSignalControllers.size() <= slot) {
769                     int nextSlot = mMobileSignalControllers.size();
770                     subs.add(addSignalController(nextSlot, nextSlot));
771                 }
772                 if (!subs.isEmpty()) {
773                     mCallbackHandler.setSubs(subs);
774                 }
775                 // Hack to index linearly for easy use.
776                 MobileSignalController controller = mMobileSignalControllers
777                         .values().toArray(new MobileSignalController[0])[slot];
778                 controller.getState().dataSim = datatype != null;
779                 if (datatype != null) {
780                     controller.getState().iconGroup =
781                             datatype.equals("1x") ? TelephonyIcons.ONE_X :
782                             datatype.equals("3g") ? TelephonyIcons.THREE_G :
783                             datatype.equals("4g") ? TelephonyIcons.FOUR_G :
784                             datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS :
785                             datatype.equals("e") ? TelephonyIcons.E :
786                             datatype.equals("g") ? TelephonyIcons.G :
787                             datatype.equals("h") ? TelephonyIcons.H :
788                             datatype.equals("lte") ? TelephonyIcons.LTE :
789                             datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS :
790                             datatype.equals("roam") ? TelephonyIcons.ROAMING :
791                             TelephonyIcons.UNKNOWN;
792                 }
793                 int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
794                 String level = args.getString("level");
795                 if (level != null) {
796                     controller.getState().level = level.equals("null") ? -1
797                             : Math.min(Integer.parseInt(level), icons[0].length - 1);
798                     controller.getState().connected = controller.getState().level >= 0;
799                 }
800                 controller.getState().enabled = show;
801                 controller.notifyListeners();
802             }
803             String carrierNetworkChange = args.getString("carriernetworkchange");
804             if (carrierNetworkChange != null) {
805                 boolean show = carrierNetworkChange.equals("show");
806                 for (MobileSignalController controller : mMobileSignalControllers.values()) {
807                     controller.setCarrierNetworkChangeMode(show);
808                 }
809             }
810         }
811     }
812 
addSignalController(int id, int simSlotIndex)813     private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
814         SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
815                 null, 0, 0, "");
816         mMobileSignalControllers.put(id, new MobileSignalController(mContext,
817                 mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info,
818                 mSubDefaults, mReceiverHandler.getLooper()));
819         return info;
820     }
821 
822     private class SubListener extends OnSubscriptionsChangedListener {
823         @Override
onSubscriptionsChanged()824         public void onSubscriptionsChanged() {
825             updateMobileControllers();
826         }
827     }
828 
829     /**
830      * Used to register listeners from the BG Looper, this way the PhoneStateListeners that
831      * get created will also run on the BG Looper.
832      */
833     private final Runnable mRegisterListeners = new Runnable() {
834         @Override
835         public void run() {
836             registerListeners();
837         }
838     };
839 
840     public static class SubscriptionDefaults {
getDefaultVoiceSubId()841         public int getDefaultVoiceSubId() {
842             return SubscriptionManager.getDefaultVoiceSubscriptionId();
843         }
844 
getDefaultDataSubId()845         public int getDefaultDataSubId() {
846             return SubscriptionManager.getDefaultDataSubscriptionId();
847         }
848     }
849 
850     @VisibleForTesting
851     static class Config {
852         boolean showAtLeast3G = false;
853         boolean alwaysShowCdmaRssi = false;
854         boolean show4gForLte = false;
855         boolean hideLtePlus = false;
856         boolean hspaDataDistinguishable;
857 
readConfig(Context context)858         static Config readConfig(Context context) {
859             Config config = new Config();
860             Resources res = context.getResources();
861 
862             config.showAtLeast3G = res.getBoolean(R.bool.config_showMin3G);
863             config.alwaysShowCdmaRssi =
864                     res.getBoolean(com.android.internal.R.bool.config_alwaysUseCdmaRssi);
865             config.show4gForLte = res.getBoolean(R.bool.config_show4GForLTE);
866             config.hspaDataDistinguishable =
867                     res.getBoolean(R.bool.config_hspa_data_distinguishable);
868             config.hideLtePlus = res.getBoolean(R.bool.config_hideLtePlus);
869             return config;
870         }
871     }
872 }
873