blob: 9734918f624c06801726e399fae1006f0e5f4c77 [file] [log] [blame]
Jason Monkda68f592015-01-07 10:55:58 -05001/*
2 * Copyright (C) 2015 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 */
16package com.android.systemui.statusbar.policy;
17
18import android.content.Context;
19import android.content.Intent;
Jason Monk0288de02017-02-23 14:48:05 -050020import android.database.ContentObserver;
Jason Monkda68f592015-01-07 10:55:58 -050021import android.net.NetworkCapabilities;
Jason Monk0288de02017-02-23 14:48:05 -050022import android.os.Handler;
Jason Monk07b75fe2015-05-14 16:47:03 -040023import android.os.Looper;
Jason Monk0288de02017-02-23 14:48:05 -050024import android.provider.Settings.Global;
Pengquan Mengf2c18a02018-12-06 17:38:38 -080025import android.telephony.NetworkRegistrationState;
Jason Monkda68f592015-01-07 10:55:58 -050026import android.telephony.PhoneStateListener;
27import android.telephony.ServiceState;
28import android.telephony.SignalStrength;
29import android.telephony.SubscriptionInfo;
30import android.telephony.SubscriptionManager;
31import android.telephony.TelephonyManager;
Jason Monk93fb68f2015-07-20 11:43:56 -040032import android.text.TextUtils;
Jason Monkda68f592015-01-07 10:55:58 -050033import android.util.Log;
34import android.util.SparseArray;
35
36import com.android.internal.annotations.VisibleForTesting;
Jason Monkda68f592015-01-07 10:55:58 -050037import com.android.internal.telephony.TelephonyIntents;
38import com.android.internal.telephony.cdma.EriInfo;
Evan Laird06e9fd82018-02-10 09:36:55 -080039import com.android.settingslib.graph.SignalDrawable;
Jason Monkda68f592015-01-07 10:55:58 -050040import com.android.systemui.R;
Jason Monk07b75fe2015-05-14 16:47:03 -040041import com.android.systemui.statusbar.policy.NetworkController.IconState;
Jason Monke06b0652016-03-02 16:35:27 -050042import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
Jason Monkda68f592015-01-07 10:55:58 -050043import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
Jason Monkc6cc6262015-06-11 11:10:15 -040044import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
Jason Monkda68f592015-01-07 10:55:58 -050045
46import java.io.PrintWriter;
Jason Monk33f8ae72015-05-08 10:45:15 -040047import java.util.BitSet;
Jason Monkda68f592015-01-07 10:55:58 -050048import java.util.Objects;
49
50
51public class MobileSignalController extends SignalController<
52 MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> {
53 private final TelephonyManager mPhone;
Jason Monkc6cc6262015-06-11 11:10:15 -040054 private final SubscriptionDefaults mDefaults;
Jason Monkda68f592015-01-07 10:55:58 -050055 private final String mNetworkNameDefault;
56 private final String mNetworkNameSeparator;
Jason Monk0288de02017-02-23 14:48:05 -050057 private final ContentObserver mObserver;
Jason Monkda68f592015-01-07 10:55:58 -050058 @VisibleForTesting
59 final PhoneStateListener mPhoneStateListener;
60 // Save entire info for logging, we only use the id.
Jason Monk66845a32015-08-03 11:09:41 -040061 final SubscriptionInfo mSubscriptionInfo;
Jason Monkda68f592015-01-07 10:55:58 -050062
63 // @VisibleForDemoMode
64 final SparseArray<MobileIconGroup> mNetworkToIconLookup;
65
66 // Since some pieces of the phone state are interdependent we store it locally,
67 // this could potentially become part of MobileState for simplification/complication
68 // of code.
Jason Monkda68f592015-01-07 10:55:58 -050069 private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
70 private int mDataState = TelephonyManager.DATA_DISCONNECTED;
71 private ServiceState mServiceState;
72 private SignalStrength mSignalStrength;
73 private MobileIconGroup mDefaultIcons;
74 private Config mConfig;
75
76 // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
77 // need listener lists anymore.
78 public MobileSignalController(Context context, Config config, boolean hasMobileData,
Jason Monk07b75fe2015-05-14 16:47:03 -040079 TelephonyManager phone, CallbackHandler callbackHandler,
Jason Monkc6cc6262015-06-11 11:10:15 -040080 NetworkControllerImpl networkController, SubscriptionInfo info,
81 SubscriptionDefaults defaults, Looper receiverLooper) {
Jason Monkda68f592015-01-07 10:55:58 -050082 super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
Jason Monk07b75fe2015-05-14 16:47:03 -040083 NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
Jason Monkda68f592015-01-07 10:55:58 -050084 networkController);
85 mNetworkToIconLookup = new SparseArray<>();
86 mConfig = config;
87 mPhone = phone;
Jason Monkc6cc6262015-06-11 11:10:15 -040088 mDefaults = defaults;
Jason Monkda68f592015-01-07 10:55:58 -050089 mSubscriptionInfo = info;
Jason Monk07b75fe2015-05-14 16:47:03 -040090 mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(),
91 receiverLooper);
Jason Monkda68f592015-01-07 10:55:58 -050092 mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
93 mNetworkNameDefault = getStringIfExists(
94 com.android.internal.R.string.lockscreen_carrier_default);
95
96 mapIconSets();
97
Jason Monk00aa9d42015-08-10 10:12:02 -040098 String networkName = info.getCarrierName() != null ? info.getCarrierName().toString()
99 : mNetworkNameDefault;
100 mLastState.networkName = mCurrentState.networkName = networkName;
101 mLastState.networkNameData = mCurrentState.networkNameData = networkName;
Jason Monkda68f592015-01-07 10:55:58 -0500102 mLastState.enabled = mCurrentState.enabled = hasMobileData;
103 mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
104 // Get initial data sim state.
105 updateDataSim();
Jason Monk0288de02017-02-23 14:48:05 -0500106 mObserver = new ContentObserver(new Handler(receiverLooper)) {
107 @Override
108 public void onChange(boolean selfChange) {
109 updateTelephony();
110 }
111 };
Jason Monkda68f592015-01-07 10:55:58 -0500112 }
113
114 public void setConfiguration(Config config) {
115 mConfig = config;
116 mapIconSets();
117 updateTelephony();
118 }
119
Jason Monkda68f592015-01-07 10:55:58 -0500120 public int getDataContentDescription() {
121 return getIcons().mDataContentDescription;
122 }
123
Jason Monkda68f592015-01-07 10:55:58 -0500124 public void setAirplaneMode(boolean airplaneMode) {
125 mCurrentState.airplaneMode = airplaneMode;
126 notifyListenersIfNecessary();
127 }
128
Jason Monkfd57ea72016-04-29 13:37:58 -0400129 public void setUserSetupComplete(boolean userSetup) {
130 mCurrentState.userSetup = userSetup;
131 notifyListenersIfNecessary();
132 }
133
Jason Monk33f8ae72015-05-08 10:45:15 -0400134 @Override
135 public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
136 boolean isValidated = validatedTransports.get(mTransportType);
137 mCurrentState.isDefault = connectedTransports.get(mTransportType);
138 // Only show this as not having connectivity if we are default.
139 mCurrentState.inetCondition = (isValidated || !mCurrentState.isDefault) ? 1 : 0;
140 notifyListenersIfNecessary();
Jason Monkda68f592015-01-07 10:55:58 -0500141 }
142
Andrew Flynna478d702015-04-14 23:33:45 -0400143 public void setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode) {
144 mCurrentState.carrierNetworkChangeMode = carrierNetworkChangeMode;
Andrew Flynn2fdbe122015-06-01 16:34:21 -0400145 updateTelephony();
Andrew Flynna478d702015-04-14 23:33:45 -0400146 }
147
Jason Monkda68f592015-01-07 10:55:58 -0500148 /**
149 * Start listening for phone state changes.
150 */
151 public void registerListener() {
152 mPhone.listen(mPhoneStateListener,
153 PhoneStateListener.LISTEN_SERVICE_STATE
154 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
155 | PhoneStateListener.LISTEN_CALL_STATE
156 | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
Andrew Flynna478d702015-04-14 23:33:45 -0400157 | PhoneStateListener.LISTEN_DATA_ACTIVITY
158 | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
Jason Monk0288de02017-02-23 14:48:05 -0500159 mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA),
160 true, mObserver);
161 mContext.getContentResolver().registerContentObserver(Global.getUriFor(
162 Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()),
163 true, mObserver);
Jason Monkda68f592015-01-07 10:55:58 -0500164 }
165
166 /**
167 * Stop listening for phone state changes.
168 */
169 public void unregisterListener() {
170 mPhone.listen(mPhoneStateListener, 0);
Jason Monk0288de02017-02-23 14:48:05 -0500171 mContext.getContentResolver().unregisterContentObserver(mObserver);
Jason Monkda68f592015-01-07 10:55:58 -0500172 }
173
174 /**
175 * Produce a mapping of data network types to icon groups for simple and quick use in
176 * updateTelephony.
177 */
178 private void mapIconSets() {
179 mNetworkToIconLookup.clear();
180
181 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G);
182 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G);
183 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G);
184 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
185 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
Wileen Chiu4105ab02015-09-18 15:17:54 -0700186 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_TD_SCDMA, TelephonyIcons.THREE_G);
Jason Monkda68f592015-01-07 10:55:58 -0500187
188 if (!mConfig.showAtLeast3G) {
189 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
190 TelephonyIcons.UNKNOWN);
191 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E);
192 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X);
193 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X);
194
195 mDefaultIcons = TelephonyIcons.G;
196 } else {
197 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
198 TelephonyIcons.THREE_G);
199 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE,
200 TelephonyIcons.THREE_G);
201 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA,
202 TelephonyIcons.THREE_G);
203 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT,
204 TelephonyIcons.THREE_G);
205 mDefaultIcons = TelephonyIcons.THREE_G;
206 }
207
208 MobileIconGroup hGroup = TelephonyIcons.THREE_G;
Amin Shaikhf5830ca2018-03-09 14:06:50 -0500209 MobileIconGroup hPlusGroup = TelephonyIcons.THREE_G;
Jason Monkda68f592015-01-07 10:55:58 -0500210 if (mConfig.hspaDataDistinguishable) {
211 hGroup = TelephonyIcons.H;
Amin Shaikhf5830ca2018-03-09 14:06:50 -0500212 hPlusGroup = TelephonyIcons.H_PLUS;
Jason Monkda68f592015-01-07 10:55:58 -0500213 }
214 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
215 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
216 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
Amin Shaikhf5830ca2018-03-09 14:06:50 -0500217 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hPlusGroup);
Jason Monkda68f592015-01-07 10:55:58 -0500218
219 if (mConfig.show4gForLte) {
220 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
Robert Greenwalt37d34ba2016-07-27 14:54:34 -0700221 if (mConfig.hideLtePlus) {
222 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
223 TelephonyIcons.FOUR_G);
224 } else {
225 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
226 TelephonyIcons.FOUR_G_PLUS);
227 }
Jason Monkda68f592015-01-07 10:55:58 -0500228 } else {
229 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
Robert Greenwalt37d34ba2016-07-27 14:54:34 -0700230 if (mConfig.hideLtePlus) {
231 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
232 TelephonyIcons.LTE);
233 } else {
234 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
235 TelephonyIcons.LTE_PLUS);
236 }
Jason Monkda68f592015-01-07 10:55:58 -0500237 }
Jason Monk7150d7f2015-07-09 10:14:12 -0400238 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
Jason Monkda68f592015-01-07 10:55:58 -0500239 }
240
Jason Monk48edc0c2017-04-10 15:01:27 -0400241 private int getNumLevels() {
Jason Monk43c14d12017-06-22 11:20:04 -0400242 if (mConfig.inflateSignalStrengths) {
243 return SignalStrength.NUM_SIGNAL_STRENGTH_BINS + 1;
244 }
Jason Monk48edc0c2017-04-10 15:01:27 -0400245 return SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
246 }
247
248 @Override
249 public int getCurrentIconId() {
250 if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) {
251 return SignalDrawable.getCarrierChangeState(getNumLevels());
252 } else if (mCurrentState.connected) {
Jason Monk43c14d12017-06-22 11:20:04 -0400253 int level = mCurrentState.level;
254 if (mConfig.inflateSignalStrengths) {
255 level++;
256 }
Amin Shaikhaf4c1932018-03-08 10:29:56 -0500257 boolean dataDisabled = mCurrentState.userSetup
258 && mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
259 boolean noInternet = mCurrentState.inetCondition == 0;
260 boolean cutOut = dataDisabled || noInternet;
261 return SignalDrawable.getState(level, getNumLevels(), cutOut);
Jason Monk48edc0c2017-04-10 15:01:27 -0400262 } else if (mCurrentState.enabled) {
263 return SignalDrawable.getEmptyState(getNumLevels());
264 } else {
265 return 0;
266 }
267 }
268
269 @Override
Jason Monk01df36f2017-06-07 13:02:47 -0400270 public int getQsCurrentIconId() {
Evan Laird3d1aad62017-06-20 16:10:44 -0400271 if (mCurrentState.airplaneMode) {
272 return SignalDrawable.getAirplaneModeState(getNumLevels());
273 }
274
Jason Monk01df36f2017-06-07 13:02:47 -0400275 return getCurrentIconId();
276 }
277
278 @Override
Jason Monke06b0652016-03-02 16:35:27 -0500279 public void notifyListeners(SignalCallback callback) {
Jason Monkda68f592015-01-07 10:55:58 -0500280 MobileIconGroup icons = getIcons();
281
282 String contentDescription = getStringIfExists(getContentDescription());
283 String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
Amin Shaikh43ad7fe2018-03-05 14:34:44 -0500284 if (mCurrentState.inetCondition == 0) {
285 dataContentDescription = mContext.getString(R.string.data_connection_no_internet);
286 }
Jason Monk7e6c83c2017-04-26 14:35:24 -0400287 final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
Jason Monkfd57ea72016-04-29 13:37:58 -0400288 && mCurrentState.userSetup;
Jeff Davidson5c7daaf2015-01-27 16:24:32 -0800289
Jason Monk0f0de132016-12-19 15:36:13 -0500290 // Show icon in QS when we are connected or data is disabled.
Jason Monk7e6c83c2017-04-26 14:35:24 -0400291 boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
Jason Monk07b75fe2015-05-14 16:47:03 -0400292 IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
293 getCurrentIconId(), contentDescription);
294
Jason Monk7e6c83c2017-04-26 14:35:24 -0400295 int qsTypeIcon = 0;
296 IconState qsIcon = null;
297 String description = null;
298 // Only send data sim callbacks to QS.
299 if (mCurrentState.dataSim) {
Evan Laird9dcd3222017-12-04 14:31:48 -0500300 qsTypeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.mQsDataType : 0;
Jason Monk7e6c83c2017-04-26 14:35:24 -0400301 qsIcon = new IconState(mCurrentState.enabled
Jason Monk01df36f2017-06-07 13:02:47 -0400302 && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
Jason Monk7e6c83c2017-04-26 14:35:24 -0400303 description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
304 }
Jason Monk07b75fe2015-05-14 16:47:03 -0400305 boolean activityIn = mCurrentState.dataConnected
Jason Monk0288de02017-02-23 14:48:05 -0500306 && !mCurrentState.carrierNetworkChangeMode
307 && mCurrentState.activityIn;
Jason Monk07b75fe2015-05-14 16:47:03 -0400308 boolean activityOut = mCurrentState.dataConnected
Jason Monk0288de02017-02-23 14:48:05 -0500309 && !mCurrentState.carrierNetworkChangeMode
310 && mCurrentState.activityOut;
Jason Monk0f0de132016-12-19 15:36:13 -0500311 showDataIcon &= mCurrentState.isDefault || dataDisabled;
Wenting Xiong63364fe2017-02-07 19:12:27 +0800312 int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.mDataType : 0;
Jason Monk7e6c83c2017-04-26 14:35:24 -0400313 callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
314 activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
315 mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);
Andrew Flynna478d702015-04-14 23:33:45 -0400316 }
317
Jason Monkda68f592015-01-07 10:55:58 -0500318 @Override
319 protected MobileState cleanState() {
320 return new MobileState();
321 }
322
323 private boolean hasService() {
324 if (mServiceState != null) {
325 // Consider the device to be in service if either voice or data
326 // service is available. Some SIM cards are marketed as data-only
327 // and do not support voice service, and on these SIM cards, we
328 // want to show signal bars for data service as well as the "no
329 // service" or "emergency calls only" text that indicates that voice
330 // is not available.
331 switch (mServiceState.getVoiceRegState()) {
332 case ServiceState.STATE_POWER_OFF:
333 return false;
334 case ServiceState.STATE_OUT_OF_SERVICE:
335 case ServiceState.STATE_EMERGENCY_ONLY:
336 return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
337 default:
338 return true;
339 }
340 } else {
341 return false;
342 }
343 }
344
345 private boolean isCdma() {
346 return (mSignalStrength != null) && !mSignalStrength.isGsm();
347 }
348
349 public boolean isEmergencyOnly() {
350 return (mServiceState != null && mServiceState.isEmergencyOnly());
351 }
352
353 private boolean isRoaming() {
Shishir Agrawal7ef5b882017-06-26 12:06:03 -0700354 // During a carrier change, roaming indications need to be supressed.
355 if (isCarrierNetworkChangeActive()) {
356 return false;
357 }
Jason Monke1531982017-09-05 11:20:30 -0400358 if (isCdma() && mServiceState != null) {
Jason Monkda68f592015-01-07 10:55:58 -0500359 final int iconMode = mServiceState.getCdmaEriIconMode();
360 return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
361 && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
Jason Monk0288de02017-02-23 14:48:05 -0500362 || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
Jason Monkda68f592015-01-07 10:55:58 -0500363 } else {
364 return mServiceState != null && mServiceState.getRoaming();
365 }
366 }
367
Andrew Flynna478d702015-04-14 23:33:45 -0400368 private boolean isCarrierNetworkChangeActive() {
Andrew Flynn55fc8002015-05-29 08:33:46 -0400369 return mCurrentState.carrierNetworkChangeMode;
Andrew Flynna478d702015-04-14 23:33:45 -0400370 }
371
Jason Monkda68f592015-01-07 10:55:58 -0500372 public void handleBroadcast(Intent intent) {
373 String action = intent.getAction();
374 if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
375 updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
376 intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700377 intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN),
Jason Monkda68f592015-01-07 10:55:58 -0500378 intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
379 intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
380 notifyListenersIfNecessary();
381 } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
382 updateDataSim();
Jason Monk8fcab352015-06-29 10:57:00 -0400383 notifyListenersIfNecessary();
Jason Monkda68f592015-01-07 10:55:58 -0500384 }
385 }
386
387 private void updateDataSim() {
Jason Monkc6cc6262015-06-11 11:10:15 -0400388 int defaultDataSub = mDefaults.getDefaultDataSubId();
Jason Monkda68f592015-01-07 10:55:58 -0500389 if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) {
390 mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId();
391 } else {
392 // There doesn't seem to be a data sim selected, however if
393 // there isn't a MobileSignalController with dataSim set, then
394 // QS won't get any callbacks and will be blank. Instead
395 // lets just assume we are the data sim (which will basically
396 // show one at random) in QS until one is selected. The user
397 // should pick one soon after, so we shouldn't be in this state
398 // for long.
399 mCurrentState.dataSim = true;
400 }
Jason Monkda68f592015-01-07 10:55:58 -0500401 }
402
403 /**
404 * Updates the network's name based on incoming spn and plmn.
405 */
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700406 void updateNetworkName(boolean showSpn, String spn, String dataSpn,
407 boolean showPlmn, String plmn) {
Jason Monkda68f592015-01-07 10:55:58 -0500408 if (CHATTY) {
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700409 Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn
410 + " spn=" + spn + " dataSpn=" + dataSpn
Jason Monkda68f592015-01-07 10:55:58 -0500411 + " showPlmn=" + showPlmn + " plmn=" + plmn);
412 }
413 StringBuilder str = new StringBuilder();
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700414 StringBuilder strData = new StringBuilder();
Jason Monkda68f592015-01-07 10:55:58 -0500415 if (showPlmn && plmn != null) {
416 str.append(plmn);
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700417 strData.append(plmn);
Jason Monkda68f592015-01-07 10:55:58 -0500418 }
419 if (showSpn && spn != null) {
420 if (str.length() != 0) {
421 str.append(mNetworkNameSeparator);
422 }
423 str.append(spn);
424 }
425 if (str.length() != 0) {
426 mCurrentState.networkName = str.toString();
427 } else {
428 mCurrentState.networkName = mNetworkNameDefault;
429 }
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700430 if (showSpn && dataSpn != null) {
431 if (strData.length() != 0) {
432 strData.append(mNetworkNameSeparator);
433 }
434 strData.append(dataSpn);
435 }
436 if (strData.length() != 0) {
437 mCurrentState.networkNameData = strData.toString();
438 } else {
439 mCurrentState.networkNameData = mNetworkNameDefault;
440 }
Jason Monkda68f592015-01-07 10:55:58 -0500441 }
442
443 /**
444 * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
445 * mDataState, and mSimState. It should be called any time one of these is updated.
446 * This will call listeners if necessary.
447 */
448 private final void updateTelephony() {
449 if (DEBUG) {
450 Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService()
451 + " ss=" + mSignalStrength);
452 }
453 mCurrentState.connected = hasService() && mSignalStrength != null;
454 if (mCurrentState.connected) {
455 if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
456 mCurrentState.level = mSignalStrength.getCdmaLevel();
457 } else {
458 mCurrentState.level = mSignalStrength.getLevel();
459 }
460 }
Pengquan Mengf2c18a02018-12-06 17:38:38 -0800461
462 // When the device is camped on a 5G Non-Standalone network, the data network type is still
463 // LTE. In this case, we first check which 5G icon should be shown.
464 MobileIconGroup nr5GIconGroup = getNr5GIconGroup();
465 if (nr5GIconGroup != null) {
466 mCurrentState.iconGroup = nr5GIconGroup;
467 } else if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
Jason Monkda68f592015-01-07 10:55:58 -0500468 mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
469 } else {
470 mCurrentState.iconGroup = mDefaultIcons;
471 }
472 mCurrentState.dataConnected = mCurrentState.connected
Jason Monk7e6c83c2017-04-26 14:35:24 -0400473 && mDataState == TelephonyManager.DATA_CONNECTED;
Jason Monkda68f592015-01-07 10:55:58 -0500474
Jason Monk0f0de132016-12-19 15:36:13 -0500475 mCurrentState.roaming = isRoaming();
Andrew Flynna478d702015-04-14 23:33:45 -0400476 if (isCarrierNetworkChangeActive()) {
477 mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
Wenting Xiong63364fe2017-02-07 19:12:27 +0800478 } else if (isDataDisabled() && !mConfig.alwaysShowDataRatIcon) {
Jason Monk7e6c83c2017-04-26 14:35:24 -0400479 mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
Jason Monkda68f592015-01-07 10:55:58 -0500480 }
481 if (isEmergencyOnly() != mCurrentState.isEmergency) {
482 mCurrentState.isEmergency = isEmergencyOnly();
483 mNetworkController.recalculateEmergency();
484 }
485 // Fill in the network name if we think we have it.
486 if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null
Jason Monk93fb68f2015-07-20 11:43:56 -0400487 && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
Jason Monkda68f592015-01-07 10:55:58 -0500488 mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
489 }
Andrew Flynna478d702015-04-14 23:33:45 -0400490
Jason Monkda68f592015-01-07 10:55:58 -0500491 notifyListenersIfNecessary();
492 }
493
Pengquan Mengf2c18a02018-12-06 17:38:38 -0800494 private MobileIconGroup getNr5GIconGroup() {
495 if (mServiceState == null) return null;
496
497 int nrStatus = mServiceState.getNrStatus();
498 if (nrStatus == NetworkRegistrationState.NR_STATUS_CONNECTED) {
499 // Check if the NR 5G is using millimeter wave and the icon is config.
500 if (mServiceState.getNrFrequencyRange() == ServiceState.FREQUENCY_RANGE_MMWAVE) {
501 if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED_MMWAVE)) {
502 return mConfig.nr5GIconMap.get(Config.NR_CONNECTED_MMWAVE);
503 }
504 }
505
506 // If NR 5G is not using millimeter wave or there is no icon for millimeter wave, we
507 // check the normal 5G icon.
508 if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED)) {
509 return mConfig.nr5GIconMap.get(Config.NR_CONNECTED);
510 }
511 } else if (nrStatus == NetworkRegistrationState.NR_STATUS_NOT_RESTRICTED) {
512 if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED)) {
513 return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED);
514 }
515 } else if (nrStatus == NetworkRegistrationState.NR_STATUS_RESTRICTED) {
516 if (mConfig.nr5GIconMap.containsKey(Config.NR_RESTRICTED)) {
517 return mConfig.nr5GIconMap.get(Config.NR_RESTRICTED);
518 }
519 }
520
521 return null;
522 }
523
Jason Monk1a95c862016-01-27 15:18:41 -0500524 private boolean isDataDisabled() {
525 return !mPhone.getDataEnabled(mSubscriptionInfo.getSubscriptionId());
526 }
527
Jason Monkda68f592015-01-07 10:55:58 -0500528 @VisibleForTesting
529 void setActivity(int activity) {
530 mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
531 || activity == TelephonyManager.DATA_ACTIVITY_IN;
532 mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
533 || activity == TelephonyManager.DATA_ACTIVITY_OUT;
534 notifyListenersIfNecessary();
535 }
536
537 @Override
538 public void dump(PrintWriter pw) {
539 super.dump(pw);
540 pw.println(" mSubscription=" + mSubscriptionInfo + ",");
541 pw.println(" mServiceState=" + mServiceState + ",");
542 pw.println(" mSignalStrength=" + mSignalStrength + ",");
543 pw.println(" mDataState=" + mDataState + ",");
544 pw.println(" mDataNetType=" + mDataNetType + ",");
545 }
546
547 class MobilePhoneStateListener extends PhoneStateListener {
Jason Monk07b75fe2015-05-14 16:47:03 -0400548 public MobilePhoneStateListener(int subId, Looper looper) {
549 super(subId, looper);
Jason Monkda68f592015-01-07 10:55:58 -0500550 }
551
552 @Override
553 public void onSignalStrengthsChanged(SignalStrength signalStrength) {
554 if (DEBUG) {
555 Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength +
556 ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
557 }
558 mSignalStrength = signalStrength;
559 updateTelephony();
560 }
561
562 @Override
563 public void onServiceStateChanged(ServiceState state) {
564 if (DEBUG) {
565 Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
566 + " dataState=" + state.getDataRegState());
567 }
568 mServiceState = state;
Jason Monke1531982017-09-05 11:20:30 -0400569 if (state != null) {
570 mDataNetType = state.getDataNetworkType();
571 if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
572 mServiceState.isUsingCarrierAggregation()) {
573 mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
574 }
Robert Greenwaltea0d71392016-07-28 18:50:10 -0700575 }
Jason Monkda68f592015-01-07 10:55:58 -0500576 updateTelephony();
577 }
578
579 @Override
580 public void onDataConnectionStateChanged(int state, int networkType) {
581 if (DEBUG) {
582 Log.d(mTag, "onDataConnectionStateChanged: state=" + state
583 + " type=" + networkType);
584 }
585 mDataState = state;
586 mDataNetType = networkType;
Robert Greenwaltea0d71392016-07-28 18:50:10 -0700587 if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
588 mServiceState.isUsingCarrierAggregation()) {
589 mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
590 }
Jason Monkda68f592015-01-07 10:55:58 -0500591 updateTelephony();
592 }
593
594 @Override
595 public void onDataActivity(int direction) {
596 if (DEBUG) {
597 Log.d(mTag, "onDataActivity: direction=" + direction);
598 }
599 setActivity(direction);
600 }
Andrew Flynna478d702015-04-14 23:33:45 -0400601
602 @Override
603 public void onCarrierNetworkChange(boolean active) {
604 if (DEBUG) {
605 Log.d(mTag, "onCarrierNetworkChange: active=" + active);
606 }
607 mCurrentState.carrierNetworkChangeMode = active;
608
609 updateTelephony();
610 }
Jason Monkda68f592015-01-07 10:55:58 -0500611 };
612
613 static class MobileIconGroup extends SignalController.IconGroup {
614 final int mDataContentDescription; // mContentDescriptionDataType
615 final int mDataType;
616 final boolean mIsWide;
Jason Monk33f8ae72015-05-08 10:45:15 -0400617 final int mQsDataType;
Jason Monkda68f592015-01-07 10:55:58 -0500618
619 public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
620 int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
Amin Shaikhd64e6262018-03-08 10:08:13 -0500621 int discContentDesc, int dataContentDesc, int dataType, boolean isWide) {
Andrew Flynn2fdbe122015-06-01 16:34:21 -0400622 super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
623 qsDiscState, discContentDesc);
Jason Monkda68f592015-01-07 10:55:58 -0500624 mDataContentDescription = dataContentDesc;
625 mDataType = dataType;
626 mIsWide = isWide;
Amin Shaikhd64e6262018-03-08 10:08:13 -0500627 mQsDataType = dataType; // TODO: remove this field
Jason Monkda68f592015-01-07 10:55:58 -0500628 }
629 }
630
631 static class MobileState extends SignalController.State {
632 String networkName;
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700633 String networkNameData;
Jason Monkda68f592015-01-07 10:55:58 -0500634 boolean dataSim;
635 boolean dataConnected;
636 boolean isEmergency;
637 boolean airplaneMode;
Andrew Flynna478d702015-04-14 23:33:45 -0400638 boolean carrierNetworkChangeMode;
Jason Monk33f8ae72015-05-08 10:45:15 -0400639 boolean isDefault;
Jason Monkfd57ea72016-04-29 13:37:58 -0400640 boolean userSetup;
Jason Monk0f0de132016-12-19 15:36:13 -0500641 boolean roaming;
Jason Monkda68f592015-01-07 10:55:58 -0500642
643 @Override
644 public void copyFrom(State s) {
645 super.copyFrom(s);
646 MobileState state = (MobileState) s;
647 dataSim = state.dataSim;
648 networkName = state.networkName;
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700649 networkNameData = state.networkNameData;
Jason Monkda68f592015-01-07 10:55:58 -0500650 dataConnected = state.dataConnected;
Jason Monk33f8ae72015-05-08 10:45:15 -0400651 isDefault = state.isDefault;
Jason Monkda68f592015-01-07 10:55:58 -0500652 isEmergency = state.isEmergency;
653 airplaneMode = state.airplaneMode;
Andrew Flynna478d702015-04-14 23:33:45 -0400654 carrierNetworkChangeMode = state.carrierNetworkChangeMode;
Jason Monkfd57ea72016-04-29 13:37:58 -0400655 userSetup = state.userSetup;
Jason Monk0f0de132016-12-19 15:36:13 -0500656 roaming = state.roaming;
Jason Monkda68f592015-01-07 10:55:58 -0500657 }
658
659 @Override
660 protected void toString(StringBuilder builder) {
661 super.toString(builder);
662 builder.append(',');
663 builder.append("dataSim=").append(dataSim).append(',');
664 builder.append("networkName=").append(networkName).append(',');
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700665 builder.append("networkNameData=").append(networkNameData).append(',');
Jason Monkda68f592015-01-07 10:55:58 -0500666 builder.append("dataConnected=").append(dataConnected).append(',');
Jason Monk0f0de132016-12-19 15:36:13 -0500667 builder.append("roaming=").append(roaming).append(',');
Jason Monk33f8ae72015-05-08 10:45:15 -0400668 builder.append("isDefault=").append(isDefault).append(',');
Jason Monkda68f592015-01-07 10:55:58 -0500669 builder.append("isEmergency=").append(isEmergency).append(',');
Andrew Flynna478d702015-04-14 23:33:45 -0400670 builder.append("airplaneMode=").append(airplaneMode).append(',');
Jason Monkfd57ea72016-04-29 13:37:58 -0400671 builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode)
672 .append(',');
673 builder.append("userSetup=").append(userSetup);
Jason Monkda68f592015-01-07 10:55:58 -0500674 }
675
676 @Override
677 public boolean equals(Object o) {
678 return super.equals(o)
679 && Objects.equals(((MobileState) o).networkName, networkName)
Pavel Zhamaitsiak5504d392015-03-27 09:24:47 -0700680 && Objects.equals(((MobileState) o).networkNameData, networkNameData)
Jason Monkda68f592015-01-07 10:55:58 -0500681 && ((MobileState) o).dataSim == dataSim
682 && ((MobileState) o).dataConnected == dataConnected
683 && ((MobileState) o).isEmergency == isEmergency
684 && ((MobileState) o).airplaneMode == airplaneMode
Andrew Flynna478d702015-04-14 23:33:45 -0400685 && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
Jason Monkfd57ea72016-04-29 13:37:58 -0400686 && ((MobileState) o).userSetup == userSetup
Jason Monk0f0de132016-12-19 15:36:13 -0500687 && ((MobileState) o).isDefault == isDefault
688 && ((MobileState) o).roaming == roaming;
Jason Monkda68f592015-01-07 10:55:58 -0500689 }
690 }
691}