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