1 /*
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  */
16 package com.android.systemui.statusbar.policy;
17 
18 import android.content.Context;
19 import android.content.Intent;
20 import android.database.ContentObserver;
21 import android.net.NetworkCapabilities;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.provider.Settings.Global;
25 import android.telephony.NetworkRegistrationInfo;
26 import android.telephony.PhoneStateListener;
27 import android.telephony.ServiceState;
28 import android.telephony.SignalStrength;
29 import android.telephony.SubscriptionInfo;
30 import android.telephony.SubscriptionManager;
31 import android.telephony.TelephonyManager;
32 import android.text.TextUtils;
33 import android.util.Log;
34 import android.util.SparseArray;
35 
36 import com.android.internal.annotations.VisibleForTesting;
37 import com.android.internal.telephony.TelephonyIntents;
38 import com.android.internal.telephony.cdma.EriInfo;
39 import com.android.settingslib.Utils;
40 import com.android.settingslib.graph.SignalDrawable;
41 import com.android.settingslib.net.SignalStrengthUtil;
42 import com.android.systemui.R;
43 import com.android.systemui.statusbar.policy.NetworkController.IconState;
44 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
45 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
46 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
47 
48 import java.io.PrintWriter;
49 import java.util.BitSet;
50 import java.util.Objects;
51 import java.util.regex.Matcher;
52 import java.util.regex.Pattern;
53 
54 
55 public class MobileSignalController extends SignalController<
56         MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> {
57     private final TelephonyManager mPhone;
58     private final SubscriptionDefaults mDefaults;
59     private final String mNetworkNameDefault;
60     private final String mNetworkNameSeparator;
61     private final ContentObserver mObserver;
62     @VisibleForTesting
63     final PhoneStateListener mPhoneStateListener;
64     // Save entire info for logging, we only use the id.
65     final SubscriptionInfo mSubscriptionInfo;
66 
67     // @VisibleForDemoMode
68     final SparseArray<MobileIconGroup> mNetworkToIconLookup;
69 
70     // Since some pieces of the phone state are interdependent we store it locally,
71     // this could potentially become part of MobileState for simplification/complication
72     // of code.
73     private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
74     private int mDataState = TelephonyManager.DATA_DISCONNECTED;
75     private ServiceState mServiceState;
76     private SignalStrength mSignalStrength;
77     private MobileIconGroup mDefaultIcons;
78     private Config mConfig;
79     @VisibleForTesting
80     boolean mInflateSignalStrengths = false;
81     // Some specific carriers have 5GE network which is special LTE CA network.
82     private static final int NETWORK_TYPE_LTE_CA_5GE = TelephonyManager.MAX_NETWORK_TYPE + 1;
83 
84     // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
85     // need listener lists anymore.
MobileSignalController(Context context, Config config, boolean hasMobileData, TelephonyManager phone, CallbackHandler callbackHandler, NetworkControllerImpl networkController, SubscriptionInfo info, SubscriptionDefaults defaults, Looper receiverLooper)86     public MobileSignalController(Context context, Config config, boolean hasMobileData,
87             TelephonyManager phone, CallbackHandler callbackHandler,
88             NetworkControllerImpl networkController, SubscriptionInfo info,
89             SubscriptionDefaults defaults, Looper receiverLooper) {
90         super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
91                 NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
92                 networkController);
93         mNetworkToIconLookup = new SparseArray<>();
94         mConfig = config;
95         mPhone = phone;
96         mDefaults = defaults;
97         mSubscriptionInfo = info;
98         mPhoneStateListener = new MobilePhoneStateListener(receiverLooper);
99         mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
100         mNetworkNameDefault = getStringIfExists(
101                 com.android.internal.R.string.lockscreen_carrier_default);
102 
103         mapIconSets();
104 
105         String networkName = info.getCarrierName() != null ? info.getCarrierName().toString()
106                 : mNetworkNameDefault;
107         mLastState.networkName = mCurrentState.networkName = networkName;
108         mLastState.networkNameData = mCurrentState.networkNameData = networkName;
109         mLastState.enabled = mCurrentState.enabled = hasMobileData;
110         mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
111         // Get initial data sim state.
112         updateDataSim();
113         mObserver = new ContentObserver(new Handler(receiverLooper)) {
114             @Override
115             public void onChange(boolean selfChange) {
116                 updateTelephony();
117             }
118         };
119     }
120 
setConfiguration(Config config)121     public void setConfiguration(Config config) {
122         mConfig = config;
123         updateInflateSignalStrength();
124         mapIconSets();
125         updateTelephony();
126     }
127 
getDataContentDescription()128     public int getDataContentDescription() {
129         return getIcons().mDataContentDescription;
130     }
131 
setAirplaneMode(boolean airplaneMode)132     public void setAirplaneMode(boolean airplaneMode) {
133         mCurrentState.airplaneMode = airplaneMode;
134         notifyListenersIfNecessary();
135     }
136 
setUserSetupComplete(boolean userSetup)137     public void setUserSetupComplete(boolean userSetup) {
138         mCurrentState.userSetup = userSetup;
139         notifyListenersIfNecessary();
140     }
141 
142     @Override
updateConnectivity(BitSet connectedTransports, BitSet validatedTransports)143     public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
144         boolean isValidated = validatedTransports.get(mTransportType);
145         mCurrentState.isDefault = connectedTransports.get(mTransportType);
146         // Only show this as not having connectivity if we are default.
147         mCurrentState.inetCondition = (isValidated || !mCurrentState.isDefault) ? 1 : 0;
148         notifyListenersIfNecessary();
149     }
150 
setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode)151     public void setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode) {
152         mCurrentState.carrierNetworkChangeMode = carrierNetworkChangeMode;
153         updateTelephony();
154     }
155 
156     /**
157      * Start listening for phone state changes.
158      */
registerListener()159     public void registerListener() {
160         mPhone.listen(mPhoneStateListener,
161                 PhoneStateListener.LISTEN_SERVICE_STATE
162                         | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
163                         | PhoneStateListener.LISTEN_CALL_STATE
164                         | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
165                         | PhoneStateListener.LISTEN_DATA_ACTIVITY
166                         | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
167         mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA),
168                 true, mObserver);
169         mContext.getContentResolver().registerContentObserver(Global.getUriFor(
170                 Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()),
171                 true, mObserver);
172     }
173 
174     /**
175      * Stop listening for phone state changes.
176      */
unregisterListener()177     public void unregisterListener() {
178         mPhone.listen(mPhoneStateListener, 0);
179         mContext.getContentResolver().unregisterContentObserver(mObserver);
180     }
181 
182     /**
183      * Produce a mapping of data network types to icon groups for simple and quick use in
184      * updateTelephony.
185      */
mapIconSets()186     private void mapIconSets() {
187         mNetworkToIconLookup.clear();
188 
189         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G);
190         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G);
191         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G);
192         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
193         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
194         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_TD_SCDMA, TelephonyIcons.THREE_G);
195 
196         if (!mConfig.showAtLeast3G) {
197             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
198                     TelephonyIcons.UNKNOWN);
199             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E);
200             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X);
201             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X);
202 
203             mDefaultIcons = TelephonyIcons.G;
204         } else {
205             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
206                     TelephonyIcons.THREE_G);
207             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE,
208                     TelephonyIcons.THREE_G);
209             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA,
210                     TelephonyIcons.THREE_G);
211             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT,
212                     TelephonyIcons.THREE_G);
213             mDefaultIcons = TelephonyIcons.THREE_G;
214         }
215 
216         MobileIconGroup hGroup = TelephonyIcons.THREE_G;
217         MobileIconGroup hPlusGroup = TelephonyIcons.THREE_G;
218         if (mConfig.hspaDataDistinguishable) {
219             hGroup = TelephonyIcons.H;
220             hPlusGroup = TelephonyIcons.H_PLUS;
221         }
222         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
223         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
224         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
225         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hPlusGroup);
226 
227         if (mConfig.show4gForLte) {
228             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
229             if (mConfig.hideLtePlus) {
230                 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
231                         TelephonyIcons.FOUR_G);
232             } else {
233                 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
234                         TelephonyIcons.FOUR_G_PLUS);
235             }
236         } else {
237             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
238             if (mConfig.hideLtePlus) {
239                 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
240                         TelephonyIcons.LTE);
241             } else {
242                 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
243                         TelephonyIcons.LTE_PLUS);
244             }
245         }
246         mNetworkToIconLookup.put(NETWORK_TYPE_LTE_CA_5GE,
247                 TelephonyIcons.LTE_CA_5G_E);
248         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
249     }
250 
updateInflateSignalStrength()251     private void updateInflateSignalStrength() {
252         mInflateSignalStrengths = SignalStrengthUtil.shouldInflateSignalStrength(mContext,
253                 mSubscriptionInfo.getSubscriptionId());
254     }
255 
getNumLevels()256     private int getNumLevels() {
257         if (mInflateSignalStrengths) {
258             return SignalStrength.NUM_SIGNAL_STRENGTH_BINS + 1;
259         }
260         return SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
261     }
262 
263     @Override
getCurrentIconId()264     public int getCurrentIconId() {
265         if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) {
266             return SignalDrawable.getCarrierChangeState(getNumLevels());
267         } else if (mCurrentState.connected) {
268             int level = mCurrentState.level;
269             if (mInflateSignalStrengths) {
270                 level++;
271             }
272             boolean dataDisabled = mCurrentState.userSetup
273                     && (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
274                     || mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA);
275             boolean noInternet = mCurrentState.inetCondition == 0;
276             boolean cutOut = dataDisabled || noInternet;
277             return SignalDrawable.getState(level, getNumLevels(), cutOut);
278         } else if (mCurrentState.enabled) {
279             return SignalDrawable.getEmptyState(getNumLevels());
280         } else {
281             return 0;
282         }
283     }
284 
285     @Override
getQsCurrentIconId()286     public int getQsCurrentIconId() {
287         return getCurrentIconId();
288     }
289 
290     @Override
notifyListeners(SignalCallback callback)291     public void notifyListeners(SignalCallback callback) {
292         MobileIconGroup icons = getIcons();
293 
294         String contentDescription = getStringIfExists(getContentDescription());
295         String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
296         if (mCurrentState.inetCondition == 0) {
297             dataContentDescription = mContext.getString(R.string.data_connection_no_internet);
298         }
299         final boolean dataDisabled = (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
300                 || mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA)
301                 && mCurrentState.userSetup;
302 
303         // Show icon in QS when we are connected or data is disabled.
304         boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
305         IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
306                 getCurrentIconId(), contentDescription);
307 
308         int qsTypeIcon = 0;
309         IconState qsIcon = null;
310         String description = null;
311         // Only send data sim callbacks to QS.
312         if (mCurrentState.dataSim) {
313             qsTypeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.mQsDataType : 0;
314             qsIcon = new IconState(mCurrentState.enabled
315                     && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
316             description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
317         }
318         boolean activityIn = mCurrentState.dataConnected
319                 && !mCurrentState.carrierNetworkChangeMode
320                 && mCurrentState.activityIn;
321         boolean activityOut = mCurrentState.dataConnected
322                 && !mCurrentState.carrierNetworkChangeMode
323                 && mCurrentState.activityOut;
324         showDataIcon &= mCurrentState.isDefault || dataDisabled;
325         int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.mDataType : 0;
326         callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
327                 activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
328                 mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);
329     }
330 
331     @Override
cleanState()332     protected MobileState cleanState() {
333         return new MobileState();
334     }
335 
isCdma()336     private boolean isCdma() {
337         return (mSignalStrength != null) && !mSignalStrength.isGsm();
338     }
339 
isEmergencyOnly()340     public boolean isEmergencyOnly() {
341         return (mServiceState != null && mServiceState.isEmergencyOnly());
342     }
343 
isRoaming()344     private boolean isRoaming() {
345         // During a carrier change, roaming indications need to be supressed.
346         if (isCarrierNetworkChangeActive()) {
347             return false;
348         }
349         if (isCdma() && mServiceState != null) {
350             final int iconMode = mServiceState.getCdmaEriIconMode();
351             return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
352                     && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
353                     || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
354         } else {
355             return mServiceState != null && mServiceState.getRoaming();
356         }
357     }
358 
isCarrierNetworkChangeActive()359     private boolean isCarrierNetworkChangeActive() {
360         return mCurrentState.carrierNetworkChangeMode;
361     }
362 
handleBroadcast(Intent intent)363     public void handleBroadcast(Intent intent) {
364         String action = intent.getAction();
365         if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
366             updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
367                     intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
368                     intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN),
369                     intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
370                     intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
371             notifyListenersIfNecessary();
372         } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
373             updateDataSim();
374             notifyListenersIfNecessary();
375         }
376     }
377 
updateDataSim()378     private void updateDataSim() {
379         int defaultDataSub = mDefaults.getDefaultDataSubId();
380         if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) {
381             mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId();
382         } else {
383             // There doesn't seem to be a data sim selected, however if
384             // there isn't a MobileSignalController with dataSim set, then
385             // QS won't get any callbacks and will be blank.  Instead
386             // lets just assume we are the data sim (which will basically
387             // show one at random) in QS until one is selected.  The user
388             // should pick one soon after, so we shouldn't be in this state
389             // for long.
390             mCurrentState.dataSim = true;
391         }
392     }
393 
isCarrierSpecificDataIcon()394     private boolean isCarrierSpecificDataIcon() {
395         if (mConfig.patternOfCarrierSpecificDataIcon == null
396                 || mConfig.patternOfCarrierSpecificDataIcon.length() == 0) {
397             return false;
398         }
399 
400         Pattern stringPattern = Pattern.compile(mConfig.patternOfCarrierSpecificDataIcon);
401         String[] operatorNames = new String[]{mServiceState.getOperatorAlphaLongRaw(),
402                 mServiceState.getOperatorAlphaShortRaw()};
403         for (String opName : operatorNames) {
404             if (!TextUtils.isEmpty(opName)) {
405                 Matcher matcher = stringPattern.matcher(opName);
406                 if (matcher.find()) {
407                     return true;
408                 }
409             }
410         }
411         return false;
412     }
413 
414     /**
415      * Updates the network's name based on incoming spn and plmn.
416      */
updateNetworkName(boolean showSpn, String spn, String dataSpn, boolean showPlmn, String plmn)417     void updateNetworkName(boolean showSpn, String spn, String dataSpn,
418             boolean showPlmn, String plmn) {
419         if (CHATTY) {
420             Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn
421                     + " spn=" + spn + " dataSpn=" + dataSpn
422                     + " showPlmn=" + showPlmn + " plmn=" + plmn);
423         }
424         StringBuilder str = new StringBuilder();
425         StringBuilder strData = new StringBuilder();
426         if (showPlmn && plmn != null) {
427             str.append(plmn);
428             strData.append(plmn);
429         }
430         if (showSpn && spn != null) {
431             if (str.length() != 0) {
432                 str.append(mNetworkNameSeparator);
433             }
434             str.append(spn);
435         }
436         if (str.length() != 0) {
437             mCurrentState.networkName = str.toString();
438         } else {
439             mCurrentState.networkName = mNetworkNameDefault;
440         }
441         if (showSpn && dataSpn != null) {
442             if (strData.length() != 0) {
443                 strData.append(mNetworkNameSeparator);
444             }
445             strData.append(dataSpn);
446         }
447         if (strData.length() != 0) {
448             mCurrentState.networkNameData = strData.toString();
449         } else {
450             mCurrentState.networkNameData = mNetworkNameDefault;
451         }
452     }
453 
454     /**
455      * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
456      * mDataState, and mSimState.  It should be called any time one of these is updated.
457      * This will call listeners if necessary.
458      */
updateTelephony()459     private final void updateTelephony() {
460         if (DEBUG) {
461             Log.d(mTag, "updateTelephonySignalStrength: hasService=" +
462                     Utils.isInService(mServiceState) + " ss=" + mSignalStrength);
463         }
464         mCurrentState.connected = Utils.isInService(mServiceState)
465                 && mSignalStrength != null;
466         if (mCurrentState.connected) {
467             if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
468                 mCurrentState.level = mSignalStrength.getCdmaLevel();
469             } else {
470                 mCurrentState.level = mSignalStrength.getLevel();
471             }
472         }
473 
474         // When the device is camped on a 5G Non-Standalone network, the data network type is still
475         // LTE. In this case, we first check which 5G icon should be shown.
476         MobileIconGroup nr5GIconGroup = getNr5GIconGroup();
477         if (nr5GIconGroup != null) {
478             mCurrentState.iconGroup = nr5GIconGroup;
479         } else if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
480             mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
481         } else {
482             mCurrentState.iconGroup = mDefaultIcons;
483         }
484         mCurrentState.dataConnected = mCurrentState.connected
485                 && mDataState == TelephonyManager.DATA_CONNECTED;
486 
487         mCurrentState.roaming = isRoaming();
488         if (isCarrierNetworkChangeActive()) {
489             mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
490         } else if (isDataDisabled() && !mConfig.alwaysShowDataRatIcon) {
491             if (mSubscriptionInfo.getSubscriptionId()
492                     != mDefaults.getDefaultDataSubId()) {
493                 mCurrentState.iconGroup = TelephonyIcons.NOT_DEFAULT_DATA;
494             } else {
495                 mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
496             }
497         }
498         if (isEmergencyOnly() != mCurrentState.isEmergency) {
499             mCurrentState.isEmergency = isEmergencyOnly();
500             mNetworkController.recalculateEmergency();
501         }
502         // Fill in the network name if we think we have it.
503         if (mCurrentState.networkName.equals(mNetworkNameDefault) && mServiceState != null
504                 && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
505             mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
506         }
507         // If this is the data subscription, update the currentState data name
508         if (mCurrentState.networkNameData.equals(mNetworkNameDefault) && mServiceState != null
509                 && mCurrentState.dataSim
510                 && !TextUtils.isEmpty(mServiceState.getDataOperatorAlphaShort())) {
511             mCurrentState.networkNameData = mServiceState.getDataOperatorAlphaShort();
512         }
513 
514         notifyListenersIfNecessary();
515     }
516 
getNr5GIconGroup()517     private MobileIconGroup getNr5GIconGroup() {
518         if (mServiceState == null) return null;
519 
520         int nrState = mServiceState.getNrState();
521         if (nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
522             // Check if the NR 5G is using millimeter wave and the icon is config.
523             if (mServiceState.getNrFrequencyRange() == ServiceState.FREQUENCY_RANGE_MMWAVE) {
524                 if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED_MMWAVE)) {
525                     return mConfig.nr5GIconMap.get(Config.NR_CONNECTED_MMWAVE);
526                 }
527             }
528 
529             // If NR 5G is not using millimeter wave or there is no icon for millimeter wave, we
530             // check the normal 5G icon.
531             if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED)) {
532                 return mConfig.nr5GIconMap.get(Config.NR_CONNECTED);
533             }
534         } else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) {
535             if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED)) {
536                 return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED);
537             }
538         } else if (nrState == NetworkRegistrationInfo.NR_STATE_RESTRICTED) {
539             if (mConfig.nr5GIconMap.containsKey(Config.NR_RESTRICTED)) {
540                 return mConfig.nr5GIconMap.get(Config.NR_RESTRICTED);
541             }
542         }
543 
544         return null;
545     }
546 
isDataDisabled()547     private boolean isDataDisabled() {
548         return !mPhone.isDataCapable();
549     }
550 
551     @VisibleForTesting
setActivity(int activity)552     void setActivity(int activity) {
553         mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
554                 || activity == TelephonyManager.DATA_ACTIVITY_IN;
555         mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
556                 || activity == TelephonyManager.DATA_ACTIVITY_OUT;
557         notifyListenersIfNecessary();
558     }
559 
560     @Override
dump(PrintWriter pw)561     public void dump(PrintWriter pw) {
562         super.dump(pw);
563         pw.println("  mSubscription=" + mSubscriptionInfo + ",");
564         pw.println("  mServiceState=" + mServiceState + ",");
565         pw.println("  mSignalStrength=" + mSignalStrength + ",");
566         pw.println("  mDataState=" + mDataState + ",");
567         pw.println("  mDataNetType=" + mDataNetType + ",");
568         pw.println("  mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
569         pw.println("  isDataDisabled=" + isDataDisabled() + ",");
570     }
571 
572     class MobilePhoneStateListener extends PhoneStateListener {
MobilePhoneStateListener(Looper looper)573         public MobilePhoneStateListener(Looper looper) {
574             super(looper);
575         }
576 
577         @Override
onSignalStrengthsChanged(SignalStrength signalStrength)578         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
579             if (DEBUG) {
580                 Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength +
581                         ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
582             }
583             mSignalStrength = signalStrength;
584             updateTelephony();
585         }
586 
587         @Override
onServiceStateChanged(ServiceState state)588         public void onServiceStateChanged(ServiceState state) {
589             if (DEBUG) {
590                 Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
591                         + " dataState=" + state.getDataRegState());
592             }
593             mServiceState = state;
594             if (mServiceState != null) {
595                 updateDataNetType(mServiceState.getDataNetworkType());
596             }
597             updateTelephony();
598         }
599 
600         @Override
onDataConnectionStateChanged(int state, int networkType)601         public void onDataConnectionStateChanged(int state, int networkType) {
602             if (DEBUG) {
603                 Log.d(mTag, "onDataConnectionStateChanged: state=" + state
604                         + " type=" + networkType);
605             }
606             mDataState = state;
607             updateDataNetType(networkType);
608             updateTelephony();
609         }
610 
updateDataNetType(int networkType)611         private void updateDataNetType(int networkType) {
612             mDataNetType = networkType;
613             if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE) {
614                 if (isCarrierSpecificDataIcon()) {
615                     mDataNetType = NETWORK_TYPE_LTE_CA_5GE;
616                 } else if (mServiceState != null && mServiceState.isUsingCarrierAggregation()) {
617                     mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
618                 }
619             }
620         }
621 
622         @Override
onDataActivity(int direction)623         public void onDataActivity(int direction) {
624             if (DEBUG) {
625                 Log.d(mTag, "onDataActivity: direction=" + direction);
626             }
627             setActivity(direction);
628         }
629 
630         @Override
onCarrierNetworkChange(boolean active)631         public void onCarrierNetworkChange(boolean active) {
632             if (DEBUG) {
633                 Log.d(mTag, "onCarrierNetworkChange: active=" + active);
634             }
635             mCurrentState.carrierNetworkChangeMode = active;
636 
637             updateTelephony();
638         }
639     };
640 
641     static class MobileIconGroup extends SignalController.IconGroup {
642         final int mDataContentDescription; // mContentDescriptionDataType
643         final int mDataType;
644         final boolean mIsWide;
645         final int mQsDataType;
646 
MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc, int sbNullState, int qsNullState, int sbDiscState, int qsDiscState, int discContentDesc, int dataContentDesc, int dataType, boolean isWide)647         public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
648                 int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
649                 int discContentDesc, int dataContentDesc, int dataType, boolean isWide) {
650             super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
651                     qsDiscState, discContentDesc);
652             mDataContentDescription = dataContentDesc;
653             mDataType = dataType;
654             mIsWide = isWide;
655             mQsDataType = dataType; // TODO: remove this field
656         }
657     }
658 
659     static class MobileState extends SignalController.State {
660         String networkName;
661         String networkNameData;
662         boolean dataSim;
663         boolean dataConnected;
664         boolean isEmergency;
665         boolean airplaneMode;
666         boolean carrierNetworkChangeMode;
667         boolean isDefault;
668         boolean userSetup;
669         boolean roaming;
670 
671         @Override
copyFrom(State s)672         public void copyFrom(State s) {
673             super.copyFrom(s);
674             MobileState state = (MobileState) s;
675             dataSim = state.dataSim;
676             networkName = state.networkName;
677             networkNameData = state.networkNameData;
678             dataConnected = state.dataConnected;
679             isDefault = state.isDefault;
680             isEmergency = state.isEmergency;
681             airplaneMode = state.airplaneMode;
682             carrierNetworkChangeMode = state.carrierNetworkChangeMode;
683             userSetup = state.userSetup;
684             roaming = state.roaming;
685         }
686 
687         @Override
toString(StringBuilder builder)688         protected void toString(StringBuilder builder) {
689             super.toString(builder);
690             builder.append(',');
691             builder.append("dataSim=").append(dataSim).append(',');
692             builder.append("networkName=").append(networkName).append(',');
693             builder.append("networkNameData=").append(networkNameData).append(',');
694             builder.append("dataConnected=").append(dataConnected).append(',');
695             builder.append("roaming=").append(roaming).append(',');
696             builder.append("isDefault=").append(isDefault).append(',');
697             builder.append("isEmergency=").append(isEmergency).append(',');
698             builder.append("airplaneMode=").append(airplaneMode).append(',');
699             builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode)
700                     .append(',');
701             builder.append("userSetup=").append(userSetup);
702         }
703 
704         @Override
equals(Object o)705         public boolean equals(Object o) {
706             return super.equals(o)
707                     && Objects.equals(((MobileState) o).networkName, networkName)
708                     && Objects.equals(((MobileState) o).networkNameData, networkNameData)
709                     && ((MobileState) o).dataSim == dataSim
710                     && ((MobileState) o).dataConnected == dataConnected
711                     && ((MobileState) o).isEmergency == isEmergency
712                     && ((MobileState) o).airplaneMode == airplaneMode
713                     && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
714                     && ((MobileState) o).userSetup == userSetup
715                     && ((MobileState) o).isDefault == isDefault
716                     && ((MobileState) o).roaming == roaming;
717         }
718     }
719 }
720