blob: 8193b52b569ca13070f7cfa8b6f851d8b595c4d6 [file] [log] [blame]
John Spurlockaf8d6c42014-05-07 17:49:08 -04001/*
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
17package com.android.systemui.statusbar.policy;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.content.res.Resources;
24import android.net.ConnectivityManager;
Lorenzo Colitti403aa262014-11-28 11:21:30 +090025import android.net.NetworkCapabilities;
John Spurlockaf8d6c42014-05-07 17:49:08 -040026import android.net.wifi.WifiManager;
John Spurlockaf8d6c42014-05-07 17:49:08 -040027import android.os.AsyncTask;
28import android.os.Bundle;
Jason Monk07b75fe2015-05-14 16:47:03 -040029import android.os.Handler;
Jason Monk30d80042015-05-08 16:54:18 -040030import android.os.Looper;
John Spurlockaf8d6c42014-05-07 17:49:08 -040031import android.provider.Settings;
Jason Monkb0808aa2015-07-22 16:34:36 -040032import android.telephony.ServiceState;
Jason Monkb5746272014-11-12 16:50:31 -050033import android.telephony.SubscriptionInfo;
34import android.telephony.SubscriptionManager;
35import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
John Spurlockaf8d6c42014-05-07 17:49:08 -040036import android.telephony.TelephonyManager;
Jason Monkb5746272014-11-12 16:50:31 -050037import android.text.TextUtils;
John Spurlockaf8d6c42014-05-07 17:49:08 -040038import android.util.Log;
John Spurlockcf053c12015-05-14 16:33:59 -040039import android.util.MathUtils;
Winsonc0d70582016-01-29 10:24:39 -080040
Jason Monke0cdb602014-11-05 12:39:45 -050041import com.android.internal.annotations.VisibleForTesting;
Jason Monkb5746272014-11-12 16:50:31 -050042import com.android.internal.telephony.PhoneConstants;
John Spurlockaf8d6c42014-05-07 17:49:08 -040043import com.android.internal.telephony.TelephonyIntents;
Jason Monkf668d7c2016-01-14 10:38:41 -050044import com.android.settingslib.net.DataUsageController;
John Spurlockaf8d6c42014-05-07 17:49:08 -040045import com.android.systemui.DemoMode;
46import com.android.systemui.R;
47
48import java.io.FileDescriptor;
49import java.io.PrintWriter;
50import java.util.ArrayList;
Lorenzo Colitti403aa262014-11-28 11:21:30 +090051import java.util.BitSet;
Jason Monkb5746272014-11-12 16:50:31 -050052import java.util.Collections;
53import java.util.Comparator;
Jason Monkd2263cd2014-11-10 14:22:56 -050054import java.util.HashMap;
John Spurlockaf8d6c42014-05-07 17:49:08 -040055import java.util.List;
56import java.util.Locale;
Jason Monkd2263cd2014-11-10 14:22:56 -050057import java.util.Map;
John Spurlockaf8d6c42014-05-07 17:49:08 -040058
Jason Monk4cf95ae2015-11-16 15:59:53 -050059import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
60
John Spurlockaf8d6c42014-05-07 17:49:08 -040061/** Platform implementation of the network controller. **/
62public class NetworkControllerImpl extends BroadcastReceiver
Jason Monkf668d7c2016-01-14 10:38:41 -050063 implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider {
John Spurlockaf8d6c42014-05-07 17:49:08 -040064 // debug
Jason Monkd2263cd2014-11-10 14:22:56 -050065 static final String TAG = "NetworkController";
66 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
67 // additional diagnostics, but not logspew
Jason Monk07b75fe2015-05-14 16:47:03 -040068 static final boolean CHATTY = Log.isLoggable(TAG + "Chat", Log.DEBUG);
John Spurlockaf8d6c42014-05-07 17:49:08 -040069
Jason Monk66845a32015-08-03 11:09:41 -040070 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
Jason Monkd2263cd2014-11-10 14:22:56 -050075 private final Context mContext;
76 private final TelephonyManager mPhone;
77 private final WifiManager mWifiManager;
78 private final ConnectivityManager mConnectivityManager;
Jason Monkb5746272014-11-12 16:50:31 -050079 private final SubscriptionManager mSubscriptionManager;
Jason Monkd2263cd2014-11-10 14:22:56 -050080 private final boolean mHasMobileDataFeature;
Jason Monkc6cc6262015-06-11 11:10:15 -040081 private final SubscriptionDefaults mSubDefaults;
Jason Monk9a4ce132016-01-21 15:27:17 -050082 private final DataSaverController mDataSaverController;
Jason Monk3aaabd72014-12-12 11:11:44 -050083 private Config mConfig;
John Spurlockaf8d6c42014-05-07 17:49:08 -040084
Jason Monkd2263cd2014-11-10 14:22:56 -050085 // Subcontrollers.
86 @VisibleForTesting
87 final WifiSignalController mWifiSignalController;
Lorenzo Colittid46bb582015-04-27 20:32:01 +090088
89 @VisibleForTesting
90 final EthernetSignalController mEthernetSignalController;
91
Jason Monkd2263cd2014-11-10 14:22:56 -050092 @VisibleForTesting
Jason Monkb5746272014-11-12 16:50:31 -050093 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;
Jason Monk0e2400f2014-11-21 11:08:55 -050098 private final AccessPointControllerImpl mAccessPoints;
Jason Monkf668d7c2016-01-14 10:38:41 -050099 private final DataUsageController mDataUsageController;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400100
Jason Monkd2263cd2014-11-10 14:22:56 -0500101 private boolean mInetCondition; // Used for Logging and demo.
Lorenzo Colitti23dd1762014-09-10 22:58:54 +0900102
Lorenzo Colitti403aa262014-11-28 11:21:30 +0900103 // 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
Jason Monkd2263cd2014-11-10 14:22:56 -0500108 // States that don't belong to a subcontroller.
John Spurlockaf8d6c42014-05-07 17:49:08 -0400109 private boolean mAirplaneMode = false;
Jason Monkb5746272014-11-12 16:50:31 -0500110 private boolean mHasNoSims;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400111 private Locale mLocale = null;
Jason Monkb5746272014-11-12 16:50:31 -0500112 // This list holds our ordering.
John Spurlockcf053c12015-05-14 16:33:59 -0400113 private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400114
Jason Monkc014dec2014-12-12 11:49:55 -0500115 @VisibleForTesting
116 boolean mListening;
John Spurlock7f8f22a2014-07-02 18:54:17 -0400117
Lorenzo Colitti403aa262014-11-28 11:21:30 +0900118 // The current user ID.
119 private int mCurrentUserId;
120
Jason Monk8fcab352015-06-29 10:57:00 -0400121 private OnSubscriptionsChangedListener mSubscriptionListener;
122
Jason Monk07b75fe2015-05-14 16:47:03 -0400123 // 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
Jason Monk66845a32015-08-03 11:09:41 -0400128 private int mEmergencySource;
129 private boolean mIsEmergency;
130
Jason Monkb0808aa2015-07-22 16:34:36 -0400131 @VisibleForTesting
132 ServiceState mLastServiceState;
133
John Spurlockaf8d6c42014-05-07 17:49:08 -0400134 /**
135 * Construct this controller object and register for updates.
136 */
Jason Monk30d80042015-05-08 16:54:18 -0400137 public NetworkControllerImpl(Context context, Looper bgLooper) {
Jason Monkf13b4b32014-11-07 16:39:34 -0500138 this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
139 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
Jason Monk29f7a7b2014-11-17 14:40:56 -0500140 (WifiManager) context.getSystemService(Context.WIFI_SERVICE),
Jason Monk07b75fe2015-05-14 16:47:03 -0400141 SubscriptionManager.from(context), Config.readConfig(context), bgLooper,
142 new CallbackHandler(),
Jason Monk30d80042015-05-08 16:54:18 -0400143 new AccessPointControllerImpl(context, bgLooper),
Jason Monkf668d7c2016-01-14 10:38:41 -0500144 new DataUsageController(context),
Jason Monkc6cc6262015-06-11 11:10:15 -0400145 new SubscriptionDefaults());
Jason Monk07b75fe2015-05-14 16:47:03 -0400146 mReceiverHandler.post(mRegisterListeners);
Jason Monkf13b4b32014-11-07 16:39:34 -0500147 }
148
149 @VisibleForTesting
150 NetworkControllerImpl(Context context, ConnectivityManager connectivityManager,
Jason Monkb5746272014-11-12 16:50:31 -0500151 TelephonyManager telephonyManager, WifiManager wifiManager,
Jason Monk07b75fe2015-05-14 16:47:03 -0400152 SubscriptionManager subManager, Config config, Looper bgLooper,
153 CallbackHandler callbackHandler,
Jason Monkd2263cd2014-11-10 14:22:56 -0500154 AccessPointControllerImpl accessPointController,
Jason Monkf668d7c2016-01-14 10:38:41 -0500155 DataUsageController dataUsageController,
Jason Monkc6cc6262015-06-11 11:10:15 -0400156 SubscriptionDefaults defaultsHandler) {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400157 mContext = context;
Jason Monkb5746272014-11-12 16:50:31 -0500158 mConfig = config;
Jason Monk07b75fe2015-05-14 16:47:03 -0400159 mReceiverHandler = new Handler(bgLooper);
160 mCallbackHandler = callbackHandler;
Jason Monk9a4ce132016-01-21 15:27:17 -0500161 mDataSaverController = new DataSaverController(context);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400162
Jason Monkb5746272014-11-12 16:50:31 -0500163 mSubscriptionManager = subManager;
Jason Monkc6cc6262015-06-11 11:10:15 -0400164 mSubDefaults = defaultsHandler;
Jason Monkf13b4b32014-11-07 16:39:34 -0500165 mConnectivityManager = connectivityManager;
166 mHasMobileDataFeature =
167 mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400168
John Spurlockaf8d6c42014-05-07 17:49:08 -0400169 // telephony
Jason Monk07b75fe2015-05-14 16:47:03 -0400170 mPhone = telephonyManager;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400171
172 // wifi
Jason Monkf13b4b32014-11-07 16:39:34 -0500173 mWifiManager = wifiManager;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400174
Jason Monkd2263cd2014-11-10 14:22:56 -0500175 mLocale = mContext.getResources().getConfiguration().locale;
Jason Monk29f7a7b2014-11-17 14:40:56 -0500176 mAccessPoints = accessPointController;
Jason Monkf668d7c2016-01-14 10:38:41 -0500177 mDataUsageController = dataUsageController;
178 mDataUsageController.setNetworkController(this);
179 // TODO: Find a way to move this into DataUsageController.
180 mDataUsageController.setCallback(new DataUsageController.Callback() {
Jason Monke0cdb602014-11-05 12:39:45 -0500181 @Override
182 public void onMobileDataEnabled(boolean enabled) {
Jason Monk07b75fe2015-05-14 16:47:03 -0400183 mCallbackHandler.setMobileDataEnabled(enabled);
Jason Monke0cdb602014-11-05 12:39:45 -0500184 }
185 });
Jason Monkd2263cd2014-11-10 14:22:56 -0500186 mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
Jason Monk07b75fe2015-05-14 16:47:03 -0400187 mCallbackHandler, this);
Jason Monkd2263cd2014-11-10 14:22:56 -0500188
Jason Monk07b75fe2015-05-14 16:47:03 -0400189 mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this);
Lorenzo Colittid46bb582015-04-27 20:32:01 +0900190
Jason Monkd2263cd2014-11-10 14:22:56 -0500191 // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
Jason Monkb5746272014-11-12 16:50:31 -0500192 updateAirplaneMode(true /* force callback */);
Jason Monke0cdb602014-11-05 12:39:45 -0500193 }
194
Jason Monk9a4ce132016-01-21 15:27:17 -0500195 public DataSaverController getDataSaverController() {
196 return mDataSaverController;
197 }
198
Jason Monkf13b4b32014-11-07 16:39:34 -0500199 private void registerListeners() {
Jason Monkb5746272014-11-12 16:50:31 -0500200 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
201 mobileSignalController.registerListener();
202 }
Jason Monk8fcab352015-06-29 10:57:00 -0400203 if (mSubscriptionListener == null) {
204 mSubscriptionListener = new SubListener();
205 }
Wink Saville071743f2015-01-12 17:11:04 -0800206 mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
Jason Monke0cdb602014-11-05 12:39:45 -0500207
John Spurlockaf8d6c42014-05-07 17:49:08 -0400208 // broadcasts
209 IntentFilter filter = new IntentFilter();
210 filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
211 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
212 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
213 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
Jason Monkb5746272014-11-12 16:50:31 -0500214 filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
215 filter.addAction(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
Jason Monkb0808aa2015-07-22 16:34:36 -0400216 filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400217 filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
Erik Kline32830cc2015-04-21 13:09:15 +0900218 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400219 filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400220 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
Jason Monk07b75fe2015-05-14 16:47:03 -0400221 mContext.registerReceiver(this, filter, null, mReceiverHandler);
Jason Monkb5746272014-11-12 16:50:31 -0500222 mListening = true;
223
224 updateMobileControllers();
John Spurlockb98f7472014-07-08 17:09:42 -0400225 }
226
Jason Monkd2263cd2014-11-10 14:22:56 -0500227 private void unregisterListeners() {
Jason Monkb5746272014-11-12 16:50:31 -0500228 mListening = false;
229 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
230 mobileSignalController.unregisterListener();
231 }
Wink Saville071743f2015-01-12 17:11:04 -0800232 mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener);
Jason Monkd2263cd2014-11-10 14:22:56 -0500233 mContext.unregisterReceiver(this);
Jason Monk5d325072014-10-27 11:38:47 -0400234 }
235
Jason Monk0e2400f2014-11-21 11:08:55 -0500236 public int getConnectedWifiLevel() {
237 return mWifiSignalController.getState().level;
238 }
239
Jason Monk5d325072014-10-27 11:38:47 -0400240 @Override
Jason Monkd2263cd2014-11-10 14:22:56 -0500241 public AccessPointController getAccessPointController() {
242 return mAccessPoints;
243 }
244
245 @Override
Jason Monkf668d7c2016-01-14 10:38:41 -0500246 public DataUsageController getMobileDataController() {
247 return mDataUsageController;
Jason Monkd2263cd2014-11-10 14:22:56 -0500248 }
249
250 public void addEmergencyListener(EmergencyListener listener) {
Jason Monk07b75fe2015-05-14 16:47:03 -0400251 mCallbackHandler.setListening(listener, true);
252 mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
John Spurlockaf8d6c42014-05-07 17:49:08 -0400253 }
254
Jason Monk46dbfb42016-02-25 14:59:20 -0500255 public void removeEmergencyListener(EmergencyListener listener) {
256 mCallbackHandler.setListening(listener, false);
257 }
258
John Spurlockaf8d6c42014-05-07 17:49:08 -0400259 public boolean hasMobileDataFeature() {
260 return mHasMobileDataFeature;
261 }
262
263 public boolean hasVoiceCallingFeature() {
264 return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
265 }
266
Jason Monkb5746272014-11-12 16:50:31 -0500267 private MobileSignalController getDataController() {
Jason Monkc6cc6262015-06-11 11:10:15 -0400268 int dataSubId = mSubDefaults.getDefaultDataSubId();
Wink Savillea54bf652014-12-11 13:37:50 -0800269 if (!SubscriptionManager.isValidSubscriptionId(dataSubId)) {
Jason Monkb5746272014-11-12 16:50:31 -0500270 if (DEBUG) Log.e(TAG, "No data sim selected");
271 return mDefaultSignalController;
272 }
273 if (mMobileSignalControllers.containsKey(dataSubId)) {
274 return mMobileSignalControllers.get(dataSubId);
275 }
Dan Sandlerc8466322014-12-08 15:42:52 -0500276 if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + dataSubId);
Jason Monkb5746272014-11-12 16:50:31 -0500277 return mDefaultSignalController;
278 }
279
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700280 public String getMobileDataNetworkName() {
Jason Monkb5746272014-11-12 16:50:31 -0500281 MobileSignalController controller = getDataController();
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700282 return controller != null ? controller.getState().networkNameData : "";
Jason Monkd2263cd2014-11-10 14:22:56 -0500283 }
284
John Spurlockaf8d6c42014-05-07 17:49:08 -0400285 public boolean isEmergencyOnly() {
Jason Monkb0808aa2015-07-22 16:34:36 -0400286 if (mMobileSignalControllers.size() == 0) {
287 // When there are no active subscriptions, determine emengency state from last
288 // broadcast.
Jason Monk66845a32015-08-03 11:09:41 -0400289 mEmergencySource = EMERGENCY_NO_CONTROLLERS;
Jason Monkb0808aa2015-07-22 16:34:36 -0400290 return mLastServiceState != null && mLastServiceState.isEmergencyOnly();
291 }
Jason Monkc6cc6262015-06-11 11:10:15 -0400292 int voiceSubId = mSubDefaults.getDefaultVoiceSubId();
Wink Savillea54bf652014-12-11 13:37:50 -0800293 if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) {
294 for (MobileSignalController mobileSignalController :
295 mMobileSignalControllers.values()) {
Jason Monkc6cc6262015-06-11 11:10:15 -0400296 if (!mobileSignalController.getState().isEmergency) {
Jason Monk66845a32015-08-03 11:09:41 -0400297 mEmergencySource = EMERGENCY_FIRST_CONTROLLER
298 + mobileSignalController.mSubscriptionInfo.getSubscriptionId();
Jason Monkc6cc6262015-06-11 11:10:15 -0400299 if (DEBUG) Log.d(TAG, "Found emergency " + mobileSignalController.mTag);
Jason Monkb5746272014-11-12 16:50:31 -0500300 return false;
301 }
302 }
303 }
304 if (mMobileSignalControllers.containsKey(voiceSubId)) {
Jason Monk66845a32015-08-03 11:09:41 -0400305 mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId;
Jason Monkc6cc6262015-06-11 11:10:15 -0400306 if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId);
307 return mMobileSignalControllers.get(voiceSubId).getState().isEmergency;
Jason Monkb5746272014-11-12 16:50:31 -0500308 }
Dan Sandlerc8466322014-12-08 15:42:52 -0500309 if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
Jason Monk66845a32015-08-03 11:09:41 -0400310 mEmergencySource = EMERGENCY_NO_SUB + voiceSubId;
Jason Monkb5746272014-11-12 16:50:31 -0500311 // Something is wrong, better assume we can't make calls...
312 return true;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400313 }
314
Jason Monkd2263cd2014-11-10 14:22:56 -0500315 /**
316 * Emergency status may have changed (triggered by MobileSignalController),
317 * so we should recheck and send out the state to listeners.
318 */
319 void recalculateEmergency() {
Jason Monk66845a32015-08-03 11:09:41 -0400320 mIsEmergency = isEmergencyOnly();
321 mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400322 }
323
Jason Monk07b75fe2015-05-14 16:47:03 -0400324 public void addSignalCallback(SignalCallback cb) {
325 mCallbackHandler.setListening(cb, true);
326 mCallbackHandler.setSubs(mCurrentSubscriptions);
327 mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
328 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
329 mCallbackHandler.setNoSims(mHasNoSims);
Jason Monkd2263cd2014-11-10 14:22:56 -0500330 mWifiSignalController.notifyListeners();
Lorenzo Colittid46bb582015-04-27 20:32:01 +0900331 mEthernetSignalController.notifyListeners();
Jason Monkb5746272014-11-12 16:50:31 -0500332 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
333 mobileSignalController.notifyListeners();
334 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400335 }
336
Jason Monk07b75fe2015-05-14 16:47:03 -0400337 @Override
338 public void removeSignalCallback(SignalCallback cb) {
339 mCallbackHandler.setListening(cb, false);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400340 }
341
342 @Override
343 public void setWifiEnabled(final boolean enabled) {
344 new AsyncTask<Void, Void, Void>() {
345 @Override
346 protected Void doInBackground(Void... args) {
347 // Disable tethering if enabling Wifi
348 final int wifiApState = mWifiManager.getWifiApState();
349 if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
Jason Monkd2263cd2014-11-10 14:22:56 -0500350 (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400351 mWifiManager.setWifiApEnabled(null, false);
352 }
353
354 mWifiManager.setWifiEnabled(enabled);
355 return null;
356 }
357 }.execute();
358 }
359
John Spurlockb98f7472014-07-08 17:09:42 -0400360 @Override
Lorenzo Colitti403aa262014-11-28 11:21:30 +0900361 public void onUserSwitched(int newUserId) {
362 mCurrentUserId = newUserId;
363 mAccessPoints.onUserSwitched(newUserId);
364 updateConnectivity();
Lorenzo Colitti403aa262014-11-28 11:21:30 +0900365 }
366
367 @Override
John Spurlockaf8d6c42014-05-07 17:49:08 -0400368 public void onReceive(Context context, Intent intent) {
Jason Monkd2263cd2014-11-10 14:22:56 -0500369 if (CHATTY) {
370 Log.d(TAG, "onReceive: intent=" + intent);
371 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400372 final String action = intent.getAction();
Erik Kline32830cc2015-04-21 13:09:15 +0900373 if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
Jason Monkd2263cd2014-11-10 14:22:56 -0500374 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
Lorenzo Colitti403aa262014-11-28 11:21:30 +0900375 updateConnectivity();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400376 } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
377 refreshLocale();
Jason Monkd2263cd2014-11-10 14:22:56 -0500378 updateAirplaneMode(false);
Jason Monkb5746272014-11-12 16:50:31 -0500379 } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED)) {
380 // We are using different subs now, we might be able to make calls.
381 recalculateEmergency();
382 } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
383 // Notify every MobileSignalController so they can know whether they are the
384 // data sim or not.
385 for (MobileSignalController controller : mMobileSignalControllers.values()) {
386 controller.handleBroadcast(intent);
387 }
388 } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
389 // Might have different subscriptions now.
390 updateMobileControllers();
Jason Monkb0808aa2015-07-22 16:34:36 -0400391 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
392 mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
393 if (mMobileSignalControllers.size() == 0) {
394 // If none of the subscriptions are active, we might need to recalculate
395 // emergency state.
396 recalculateEmergency();
397 }
Jason Monkb5746272014-11-12 16:50:31 -0500398 } else {
399 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
400 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
Wink Savillea54bf652014-12-11 13:37:50 -0800401 if (SubscriptionManager.isValidSubscriptionId(subId)) {
Jason Monkb5746272014-11-12 16:50:31 -0500402 if (mMobileSignalControllers.containsKey(subId)) {
403 mMobileSignalControllers.get(subId).handleBroadcast(intent);
404 } else {
405 // Can't find this subscription... We must be out of date.
406 updateMobileControllers();
407 }
408 } else {
409 // No sub id, must be for the wifi.
410 mWifiSignalController.handleBroadcast(intent);
411 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400412 }
Jason Monkb5746272014-11-12 16:50:31 -0500413 }
414
Jason Monk1c040db2015-07-20 09:45:54 -0400415 public void onConfigurationChanged() {
Sungmin Choi6be4f6b2015-07-07 13:06:59 +0900416 mConfig = Config.readConfig(mContext);
Jason Monk1c040db2015-07-20 09:45:54 -0400417 mReceiverHandler.post(new Runnable() {
418 @Override
419 public void run() {
420 handleConfigurationChanged();
421 }
422 });
423 }
424
425 @VisibleForTesting
426 void handleConfigurationChanged() {
Jason Monk3aaabd72014-12-12 11:11:44 -0500427 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
428 mobileSignalController.setConfiguration(mConfig);
429 }
430 refreshLocale();
Jason Monk3aaabd72014-12-12 11:11:44 -0500431 }
432
Jason Monkb5746272014-11-12 16:50:31 -0500433 private void updateMobileControllers() {
434 if (!mListening) {
435 return;
436 }
Jason Monkc6cc6262015-06-11 11:10:15 -0400437 doUpdateMobileControllers();
438 }
439
440 @VisibleForTesting
441 void doUpdateMobileControllers() {
Jason Monkb5746272014-11-12 16:50:31 -0500442 List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList();
Jason Monkc9f05712014-12-15 12:24:10 -0500443 if (subscriptions == null) {
444 subscriptions = Collections.emptyList();
445 }
Jason Monkb5746272014-11-12 16:50:31 -0500446 // If there have been no relevant changes to any of the subscriptions, we can leave as is.
447 if (hasCorrectMobileControllers(subscriptions)) {
448 // Even if the controllers are correct, make sure we have the right no sims state.
449 // Such as on boot, don't need any controllers, because there are no sims,
450 // but we still need to update the no sim state.
451 updateNoSims();
452 return;
453 }
454 setCurrentSubscriptions(subscriptions);
455 updateNoSims();
Jason Monkc6cc6262015-06-11 11:10:15 -0400456 recalculateEmergency();
Jason Monkb5746272014-11-12 16:50:31 -0500457 }
458
Jason Monk21d05a02014-12-02 12:46:58 -0500459 @VisibleForTesting
460 protected void updateNoSims() {
461 boolean hasNoSims = mHasMobileDataFeature && mMobileSignalControllers.size() == 0;
Jason Monkb5746272014-11-12 16:50:31 -0500462 if (hasNoSims != mHasNoSims) {
463 mHasNoSims = hasNoSims;
Jason Monk259e06f2015-06-18 14:07:26 -0400464 mCallbackHandler.setNoSims(mHasNoSims);
Jason Monkb5746272014-11-12 16:50:31 -0500465 }
466 }
467
468 @VisibleForTesting
469 void setCurrentSubscriptions(List<SubscriptionInfo> subscriptions) {
470 Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() {
471 @Override
472 public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) {
473 return lhs.getSimSlotIndex() == rhs.getSimSlotIndex()
474 ? lhs.getSubscriptionId() - rhs.getSubscriptionId()
475 : lhs.getSimSlotIndex() - rhs.getSimSlotIndex();
476 }
477 });
Jason Monkb5746272014-11-12 16:50:31 -0500478 mCurrentSubscriptions = subscriptions;
479
480 HashMap<Integer, MobileSignalController> cachedControllers =
481 new HashMap<Integer, MobileSignalController>(mMobileSignalControllers);
482 mMobileSignalControllers.clear();
483 final int num = subscriptions.size();
484 for (int i = 0; i < num; i++) {
485 int subId = subscriptions.get(i).getSubscriptionId();
486 // If we have a copy of this controller already reuse it, otherwise make a new one.
487 if (cachedControllers.containsKey(subId)) {
Jason Monkc014dec2014-12-12 11:49:55 -0500488 mMobileSignalControllers.put(subId, cachedControllers.remove(subId));
Jason Monkb5746272014-11-12 16:50:31 -0500489 } else {
490 MobileSignalController controller = new MobileSignalController(mContext, mConfig,
Jason Monk07b75fe2015-05-14 16:47:03 -0400491 mHasMobileDataFeature, mPhone, mCallbackHandler,
Jason Monkc6cc6262015-06-11 11:10:15 -0400492 this, subscriptions.get(i), mSubDefaults, mReceiverHandler.getLooper());
Jason Monkb5746272014-11-12 16:50:31 -0500493 mMobileSignalControllers.put(subId, controller);
494 if (subscriptions.get(i).getSimSlotIndex() == 0) {
495 mDefaultSignalController = controller;
496 }
497 if (mListening) {
498 controller.registerListener();
499 }
500 }
501 }
502 if (mListening) {
503 for (Integer key : cachedControllers.keySet()) {
504 if (cachedControllers.get(key) == mDefaultSignalController) {
505 mDefaultSignalController = null;
506 }
507 cachedControllers.get(key).unregisterListener();
508 }
509 }
Jason Monk8fcab352015-06-29 10:57:00 -0400510 mCallbackHandler.setSubs(subscriptions);
511 notifyAllListeners();
512
Jason Monk25d8a482014-12-09 12:27:24 -0500513 // There may be new MobileSignalControllers around, make sure they get the current
514 // inet condition and airplane mode.
515 pushConnectivityToSignals();
516 updateAirplaneMode(true /* force */);
Jason Monkb5746272014-11-12 16:50:31 -0500517 }
518
Jason Monkc014dec2014-12-12 11:49:55 -0500519 @VisibleForTesting
520 boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) {
Jason Monkc9f05712014-12-15 12:24:10 -0500521 if (allSubscriptions.size() != mMobileSignalControllers.size()) {
522 return false;
Jason Monkb5746272014-11-12 16:50:31 -0500523 }
524 for (SubscriptionInfo info : allSubscriptions) {
525 if (!mMobileSignalControllers.containsKey(info.getSubscriptionId())) {
526 return false;
527 }
528 }
529 return true;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400530 }
531
Jason Monkd2263cd2014-11-10 14:22:56 -0500532 private void updateAirplaneMode(boolean force) {
533 boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
534 Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
535 if (airplaneMode != mAirplaneMode || force) {
536 mAirplaneMode = airplaneMode;
Jason Monkb5746272014-11-12 16:50:31 -0500537 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
538 mobileSignalController.setAirplaneMode(mAirplaneMode);
539 }
540 notifyListeners();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400541 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400542 }
543
544 private void refreshLocale() {
Jason Monkd2263cd2014-11-10 14:22:56 -0500545 Locale current = mContext.getResources().getConfiguration().locale;
Jason Monkb5746272014-11-12 16:50:31 -0500546 if (!current.equals(mLocale)) {
Jason Monkd2263cd2014-11-10 14:22:56 -0500547 mLocale = current;
548 notifyAllListeners();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400549 }
550 }
551
Jason Monkd2263cd2014-11-10 14:22:56 -0500552 /**
Jason Monkb5746272014-11-12 16:50:31 -0500553 * Forces update of all callbacks on both SignalClusters and
554 * NetworkSignalChangedCallbacks.
555 */
Jason Monkd2263cd2014-11-10 14:22:56 -0500556 private void notifyAllListeners() {
Jason Monkb5746272014-11-12 16:50:31 -0500557 notifyListeners();
558 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
559 mobileSignalController.notifyListeners();
560 }
Jason Monkd2263cd2014-11-10 14:22:56 -0500561 mWifiSignalController.notifyListeners();
Lorenzo Colittid46bb582015-04-27 20:32:01 +0900562 mEthernetSignalController.notifyListeners();
Jason Monkd2263cd2014-11-10 14:22:56 -0500563 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400564
Jason Monkb5746272014-11-12 16:50:31 -0500565 /**
566 * Notifies listeners of changes in state of to the NetworkController, but
567 * does not notify for any info on SignalControllers, for that call
568 * notifyAllListeners.
569 */
570 private void notifyListeners() {
Jason Monk07b75fe2015-05-14 16:47:03 -0400571 mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
572 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
573 mCallbackHandler.setNoSims(mHasNoSims);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400574 }
575
Jason Monkd2263cd2014-11-10 14:22:56 -0500576 /**
577 * Update the Inet conditions and what network we are connected to.
578 */
Lorenzo Colitti403aa262014-11-28 11:21:30 +0900579 private void updateConnectivity() {
580 mConnectedTransports.clear();
581 mValidatedTransports.clear();
582 for (NetworkCapabilities nc :
583 mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) {
584 for (int transportType : nc.getTransportTypes()) {
585 mConnectedTransports.set(transportType);
586 if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) {
587 mValidatedTransports.set(transportType);
588 }
589 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400590 }
591
John Spurlockaf8d6c42014-05-07 17:49:08 -0400592 if (CHATTY) {
Lorenzo Colitti403aa262014-11-28 11:21:30 +0900593 Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports);
594 Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400595 }
596
Lorenzo Colitti403aa262014-11-28 11:21:30 +0900597 mInetCondition = !mValidatedTransports.isEmpty();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400598
Jason Monk25d8a482014-12-09 12:27:24 -0500599 pushConnectivityToSignals();
600 }
601
602 /**
603 * Pushes the current connectivity state to all SignalControllers.
604 */
605 private void pushConnectivityToSignals() {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400606 // We want to update all the icons, all at once, for any condition change
Jason Monkb5746272014-11-12 16:50:31 -0500607 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
Jason Monk33f8ae72015-05-08 10:45:15 -0400608 mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
Jason Monkb5746272014-11-12 16:50:31 -0500609 }
Jason Monk33f8ae72015-05-08 10:45:15 -0400610 mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
611 mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400612 }
613
John Spurlockaf8d6c42014-05-07 17:49:08 -0400614 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
615 pw.println("NetworkController state:");
Lorenzo Colitti403aa262014-11-28 11:21:30 +0900616
John Spurlockaf8d6c42014-05-07 17:49:08 -0400617 pw.println(" - telephony ------");
618 pw.print(" hasVoiceCallingFeature()=");
619 pw.println(hasVoiceCallingFeature());
John Spurlockaf8d6c42014-05-07 17:49:08 -0400620
John Spurlockaf8d6c42014-05-07 17:49:08 -0400621 pw.println(" - connectivity ------");
Lorenzo Colitti403aa262014-11-28 11:21:30 +0900622 pw.print(" mConnectedTransports=");
623 pw.println(mConnectedTransports);
624 pw.print(" mValidatedTransports=");
625 pw.println(mValidatedTransports);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400626 pw.print(" mInetCondition=");
627 pw.println(mInetCondition);
Jason Monkd2263cd2014-11-10 14:22:56 -0500628 pw.print(" mAirplaneMode=");
629 pw.println(mAirplaneMode);
630 pw.print(" mLocale=");
631 pw.println(mLocale);
Jason Monkb0808aa2015-07-22 16:34:36 -0400632 pw.print(" mLastServiceState=");
633 pw.println(mLastServiceState);
Jason Monk66845a32015-08-03 11:09:41 -0400634 pw.print(" mIsEmergency=");
635 pw.println(mIsEmergency);
636 pw.print(" mEmergencySource=");
637 pw.println(emergencyToString(mEmergencySource));
John Spurlockaf8d6c42014-05-07 17:49:08 -0400638
Jason Monkb5746272014-11-12 16:50:31 -0500639 for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
640 mobileSignalController.dump(pw);
641 }
Jason Monkd2263cd2014-11-10 14:22:56 -0500642 mWifiSignalController.dump(pw);
Jason Monkd52356a2015-01-28 10:40:41 -0500643
Lorenzo Colittid46bb582015-04-27 20:32:01 +0900644 mEthernetSignalController.dump(pw);
645
Jason Monkd52356a2015-01-28 10:40:41 -0500646 mAccessPoints.dump(pw);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400647 }
648
Jason Monk66845a32015-08-03 11:09:41 -0400649 private static final String emergencyToString(int emergencySource) {
650 if (emergencySource > EMERGENCY_NO_SUB) {
651 return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")";
652 } else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) {
653 return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")";
654 } else if (emergencySource > EMERGENCY_FIRST_CONTROLLER) {
655 return "FIRST_CONTROLLER(" + (emergencySource - EMERGENCY_FIRST_CONTROLLER) + ")";
656 } else if (emergencySource == EMERGENCY_NO_CONTROLLERS) {
657 return "NO_CONTROLLERS";
658 }
659 return "UNKNOWN_SOURCE";
660 }
661
John Spurlockaf8d6c42014-05-07 17:49:08 -0400662 private boolean mDemoMode;
Jason Monk33f8ae72015-05-08 10:45:15 -0400663 private boolean mDemoInetCondition;
Jason Monkd2263cd2014-11-10 14:22:56 -0500664 private WifiSignalController.WifiState mDemoWifiState;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400665
666 @Override
667 public void dispatchDemoCommand(String command, Bundle args) {
668 if (!mDemoMode && command.equals(COMMAND_ENTER)) {
Jason Monkd2263cd2014-11-10 14:22:56 -0500669 if (DEBUG) Log.d(TAG, "Entering demo mode");
670 unregisterListeners();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400671 mDemoMode = true;
Jason Monk33f8ae72015-05-08 10:45:15 -0400672 mDemoInetCondition = mInetCondition;
Jason Monkd2263cd2014-11-10 14:22:56 -0500673 mDemoWifiState = mWifiSignalController.getState();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400674 } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
Jason Monkd2263cd2014-11-10 14:22:56 -0500675 if (DEBUG) Log.d(TAG, "Exiting demo mode");
John Spurlockaf8d6c42014-05-07 17:49:08 -0400676 mDemoMode = false;
Jason Monkb5746272014-11-12 16:50:31 -0500677 // Update what MobileSignalControllers, because they may change
678 // to set the number of sim slots.
679 updateMobileControllers();
680 for (MobileSignalController controller : mMobileSignalControllers.values()) {
681 controller.resetLastState();
682 }
Jason Monkd2263cd2014-11-10 14:22:56 -0500683 mWifiSignalController.resetLastState();
Jason Monk07b75fe2015-05-14 16:47:03 -0400684 mReceiverHandler.post(mRegisterListeners);
Jason Monkd2263cd2014-11-10 14:22:56 -0500685 notifyAllListeners();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400686 } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
687 String airplane = args.getString("airplane");
688 if (airplane != null) {
689 boolean show = airplane.equals("show");
Jason Monk07b75fe2015-05-14 16:47:03 -0400690 mCallbackHandler.setIsAirplaneMode(new IconState(show,
691 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode,
692 mContext));
John Spurlockaf8d6c42014-05-07 17:49:08 -0400693 }
694 String fully = args.getString("fully");
695 if (fully != null) {
Jason Monk33f8ae72015-05-08 10:45:15 -0400696 mDemoInetCondition = Boolean.parseBoolean(fully);
697 BitSet connected = new BitSet();
698
699 if (mDemoInetCondition) {
700 connected.set(mWifiSignalController.mTransportType);
701 }
702 mWifiSignalController.updateConnectivity(connected, connected);
Jason Monkb5746272014-11-12 16:50:31 -0500703 for (MobileSignalController controller : mMobileSignalControllers.values()) {
Jason Monk33f8ae72015-05-08 10:45:15 -0400704 if (mDemoInetCondition) {
705 connected.set(controller.mTransportType);
706 }
707 controller.updateConnectivity(connected, connected);
Jason Monkb5746272014-11-12 16:50:31 -0500708 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400709 }
710 String wifi = args.getString("wifi");
711 if (wifi != null) {
712 boolean show = wifi.equals("show");
713 String level = args.getString("level");
714 if (level != null) {
Jason Monkd2263cd2014-11-10 14:22:56 -0500715 mDemoWifiState.level = level.equals("null") ? -1
John Spurlockaf8d6c42014-05-07 17:49:08 -0400716 : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
Jason Monkd2263cd2014-11-10 14:22:56 -0500717 mDemoWifiState.connected = mDemoWifiState.level >= 0;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400718 }
Jason Monkd2263cd2014-11-10 14:22:56 -0500719 mDemoWifiState.enabled = show;
720 mWifiSignalController.notifyListeners();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400721 }
Jason Monkb5746272014-11-12 16:50:31 -0500722 String sims = args.getString("sims");
723 if (sims != null) {
John Spurlockcf053c12015-05-14 16:33:59 -0400724 int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8);
725 List<SubscriptionInfo> subs = new ArrayList<>();
Jason Monkb5746272014-11-12 16:50:31 -0500726 if (num != mMobileSignalControllers.size()) {
727 mMobileSignalControllers.clear();
728 int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
729 for (int i = start /* get out of normal index range */; i < start + num; i++) {
John Spurlockcf053c12015-05-14 16:33:59 -0400730 subs.add(addSignalController(i, i));
Jason Monkb5746272014-11-12 16:50:31 -0500731 }
Jason Monk33b60bb2015-07-13 10:42:23 -0400732 mCallbackHandler.setSubs(subs);
Jason Monkb5746272014-11-12 16:50:31 -0500733 }
Jason Monkb5746272014-11-12 16:50:31 -0500734 }
735 String nosim = args.getString("nosim");
736 if (nosim != null) {
Jason Monk259e06f2015-06-18 14:07:26 -0400737 mHasNoSims = nosim.equals("show");
738 mCallbackHandler.setNoSims(mHasNoSims);
Jason Monkb5746272014-11-12 16:50:31 -0500739 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400740 String mobile = args.getString("mobile");
741 if (mobile != null) {
742 boolean show = mobile.equals("show");
743 String datatype = args.getString("datatype");
Jason Monkb5746272014-11-12 16:50:31 -0500744 String slotString = args.getString("slot");
745 int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString);
John Spurlockcf053c12015-05-14 16:33:59 -0400746 slot = MathUtils.constrain(slot, 0, 8);
747 // Ensure we have enough sim slots
748 List<SubscriptionInfo> subs = new ArrayList<>();
749 while (mMobileSignalControllers.size() <= slot) {
750 int nextSlot = mMobileSignalControllers.size();
751 subs.add(addSignalController(nextSlot, nextSlot));
752 }
753 if (!subs.isEmpty()) {
Jason Monk07b75fe2015-05-14 16:47:03 -0400754 mCallbackHandler.setSubs(subs);
John Spurlockcf053c12015-05-14 16:33:59 -0400755 }
Jason Monkb5746272014-11-12 16:50:31 -0500756 // Hack to index linearly for easy use.
757 MobileSignalController controller = mMobileSignalControllers
758 .values().toArray(new MobileSignalController[0])[slot];
759 controller.getState().dataSim = datatype != null;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400760 if (datatype != null) {
Jason Monkb5746272014-11-12 16:50:31 -0500761 controller.getState().iconGroup =
Jason Monkd2263cd2014-11-10 14:22:56 -0500762 datatype.equals("1x") ? TelephonyIcons.ONE_X :
763 datatype.equals("3g") ? TelephonyIcons.THREE_G :
764 datatype.equals("4g") ? TelephonyIcons.FOUR_G :
765 datatype.equals("e") ? TelephonyIcons.E :
766 datatype.equals("g") ? TelephonyIcons.G :
767 datatype.equals("h") ? TelephonyIcons.H :
768 datatype.equals("lte") ? TelephonyIcons.LTE :
769 datatype.equals("roam") ? TelephonyIcons.ROAMING :
770 TelephonyIcons.UNKNOWN;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400771 }
772 int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
773 String level = args.getString("level");
774 if (level != null) {
Jason Monkb5746272014-11-12 16:50:31 -0500775 controller.getState().level = level.equals("null") ? -1
John Spurlockaf8d6c42014-05-07 17:49:08 -0400776 : Math.min(Integer.parseInt(level), icons[0].length - 1);
Jason Monkb5746272014-11-12 16:50:31 -0500777 controller.getState().connected = controller.getState().level >= 0;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400778 }
Jason Monkb5746272014-11-12 16:50:31 -0500779 controller.getState().enabled = show;
780 controller.notifyListeners();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400781 }
Andrew Flynna478d702015-04-14 23:33:45 -0400782 String carrierNetworkChange = args.getString("carriernetworkchange");
783 if (carrierNetworkChange != null) {
784 boolean show = carrierNetworkChange.equals("show");
785 for (MobileSignalController controller : mMobileSignalControllers.values()) {
786 controller.setCarrierNetworkChangeMode(show);
787 }
788 }
Jason Monkd2263cd2014-11-10 14:22:56 -0500789 }
790 }
791
John Spurlockcf053c12015-05-14 16:33:59 -0400792 private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
793 SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
794 null, 0, 0, "");
795 mMobileSignalControllers.put(id, new MobileSignalController(mContext,
Jason Monk07b75fe2015-05-14 16:47:03 -0400796 mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info,
Jason Monkc6cc6262015-06-11 11:10:15 -0400797 mSubDefaults, mReceiverHandler.getLooper()));
John Spurlockcf053c12015-05-14 16:33:59 -0400798 return info;
799 }
800
Jason Monk8fcab352015-06-29 10:57:00 -0400801 private class SubListener extends OnSubscriptionsChangedListener {
Jason Monkc9f05712014-12-15 12:24:10 -0500802 @Override
803 public void onSubscriptionsChanged() {
Jason Monkb5746272014-11-12 16:50:31 -0500804 updateMobileControllers();
Jason Monk8fcab352015-06-29 10:57:00 -0400805 }
806 }
Jason Monkb5746272014-11-12 16:50:31 -0500807
Jason Monk07b75fe2015-05-14 16:47:03 -0400808 /**
809 * Used to register listeners from the BG Looper, this way the PhoneStateListeners that
810 * get created will also run on the BG Looper.
811 */
812 private final Runnable mRegisterListeners = new Runnable() {
813 @Override
814 public void run() {
815 registerListeners();
816 }
817 };
Jason Monkd2263cd2014-11-10 14:22:56 -0500818
Jason Monkc6cc6262015-06-11 11:10:15 -0400819 public static class SubscriptionDefaults {
820 public int getDefaultVoiceSubId() {
Shishir Agrawal7ea3e8b2016-01-25 13:03:07 -0800821 return SubscriptionManager.getDefaultVoiceSubscriptionId();
Jason Monkc6cc6262015-06-11 11:10:15 -0400822 }
823
824 public int getDefaultDataSubId() {
Shishir Agrawal7ea3e8b2016-01-25 13:03:07 -0800825 return SubscriptionManager.getDefaultDataSubscriptionId();
Jason Monkc6cc6262015-06-11 11:10:15 -0400826 }
827 }
828
Jason Monkd2263cd2014-11-10 14:22:56 -0500829 @VisibleForTesting
830 static class Config {
Jason Monkb5746272014-11-12 16:50:31 -0500831 boolean showAtLeast3G = false;
Jason Monkd2263cd2014-11-10 14:22:56 -0500832 boolean alwaysShowCdmaRssi = false;
833 boolean show4gForLte = false;
834 boolean hspaDataDistinguishable;
835
836 static Config readConfig(Context context) {
837 Config config = new Config();
838 Resources res = context.getResources();
839
Jason Monkb5746272014-11-12 16:50:31 -0500840 config.showAtLeast3G = res.getBoolean(R.bool.config_showMin3G);
Jason Monkd2263cd2014-11-10 14:22:56 -0500841 config.alwaysShowCdmaRssi =
842 res.getBoolean(com.android.internal.R.bool.config_alwaysUseCdmaRssi);
843 config.show4gForLte = res.getBoolean(R.bool.config_show4GForLTE);
844 config.hspaDataDistinguishable =
845 res.getBoolean(R.bool.config_hspa_data_distinguishable);
846 return config;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400847 }
848 }
849}