• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.CdmaEriInformation;
27 import android.telephony.CellSignalStrength;
28 import android.telephony.CellSignalStrengthCdma;
29 import android.telephony.PhoneStateListener;
30 import android.telephony.ServiceState;
31 import android.telephony.SignalStrength;
32 import android.telephony.SubscriptionInfo;
33 import android.telephony.SubscriptionManager;
34 import android.telephony.TelephonyDisplayInfo;
35 import android.telephony.TelephonyManager;
36 import android.text.Html;
37 import android.text.TextUtils;
38 import android.util.Log;
39 
40 import com.android.internal.annotations.VisibleForTesting;
41 import com.android.settingslib.Utils;
42 import com.android.settingslib.graph.SignalDrawable;
43 import com.android.settingslib.net.SignalStrengthUtil;
44 import com.android.systemui.R;
45 import com.android.systemui.statusbar.policy.NetworkController.IconState;
46 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
47 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
48 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
49 
50 import java.io.PrintWriter;
51 import java.util.BitSet;
52 import java.util.HashMap;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Objects;
56 import java.util.concurrent.Executor;
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((new Handler(receiverLooper))::post);
103         mNetworkNameSeparator = getTextIfExists(R.string.status_bar_network_name_separator)
104                 .toString();
105         mNetworkNameDefault = getTextIfExists(
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         mNetworkToIconLookup.put(toIconKey(
288                 TelephonyManager.NETWORK_TYPE_NR),
289                 TelephonyIcons.NR_5G);
290     }
291 
getIconKey()292     private String getIconKey() {
293         if (mTelephonyDisplayInfo.getOverrideNetworkType()
294                 == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE) {
295             return toIconKey(mTelephonyDisplayInfo.getNetworkType());
296         } else {
297             return toDisplayIconKey(mTelephonyDisplayInfo.getOverrideNetworkType());
298         }
299     }
300 
toIconKey(@nnotation.NetworkType int networkType)301     private String toIconKey(@Annotation.NetworkType int networkType) {
302         return Integer.toString(networkType);
303     }
304 
toDisplayIconKey(@nnotation.OverrideNetworkType int displayNetworkType)305     private String toDisplayIconKey(@Annotation.OverrideNetworkType int displayNetworkType) {
306         switch (displayNetworkType) {
307             case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA:
308                 return toIconKey(TelephonyManager.NETWORK_TYPE_LTE) + "_CA";
309             case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO:
310                 return toIconKey(TelephonyManager.NETWORK_TYPE_LTE) + "_CA_Plus";
311             case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA:
312                 return toIconKey(TelephonyManager.NETWORK_TYPE_NR);
313             case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE:
314                 return toIconKey(TelephonyManager.NETWORK_TYPE_NR) + "_Plus";
315             default:
316                 return "unsupported";
317         }
318     }
319 
updateInflateSignalStrength()320     private void updateInflateSignalStrength() {
321         mInflateSignalStrengths = SignalStrengthUtil.shouldInflateSignalStrength(mContext,
322                 mSubscriptionInfo.getSubscriptionId());
323     }
324 
getNumLevels()325     private int getNumLevels() {
326         if (mInflateSignalStrengths) {
327             return CellSignalStrength.getNumSignalStrengthLevels() + 1;
328         }
329         return CellSignalStrength.getNumSignalStrengthLevels();
330     }
331 
332     @Override
getCurrentIconId()333     public int getCurrentIconId() {
334         if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) {
335             return SignalDrawable.getCarrierChangeState(getNumLevels());
336         } else if (mCurrentState.connected) {
337             int level = mCurrentState.level;
338             if (mInflateSignalStrengths) {
339                 level++;
340             }
341             boolean dataDisabled = mCurrentState.userSetup
342                     && (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
343                     || (mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA
344                             && mCurrentState.defaultDataOff));
345             boolean noInternet = mCurrentState.inetCondition == 0;
346             boolean cutOut = dataDisabled || noInternet;
347             return SignalDrawable.getState(level, getNumLevels(), cutOut);
348         } else if (mCurrentState.enabled) {
349             return SignalDrawable.getEmptyState(getNumLevels());
350         } else {
351             return 0;
352         }
353     }
354 
355     @Override
getQsCurrentIconId()356     public int getQsCurrentIconId() {
357         return getCurrentIconId();
358     }
359 
360     @Override
notifyListeners(SignalCallback callback)361     public void notifyListeners(SignalCallback callback) {
362         MobileIconGroup icons = getIcons();
363 
364         String contentDescription = getTextIfExists(getContentDescription()).toString();
365         CharSequence dataContentDescriptionHtml = getTextIfExists(icons.mDataContentDescription);
366 
367         //TODO: Hacky
368         // The data content description can sometimes be shown in a text view and might come to us
369         // as HTML. Strip any styling here so that listeners don't have to care
370         CharSequence dataContentDescription = Html.fromHtml(
371                 dataContentDescriptionHtml.toString(), 0).toString();
372         if (mCurrentState.inetCondition == 0) {
373             dataContentDescription = mContext.getString(R.string.data_connection_no_internet);
374         }
375         final boolean dataDisabled = (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
376                 || (mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA))
377                 && mCurrentState.userSetup;
378 
379         // Show icon in QS when we are connected or data is disabled.
380         boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
381         IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
382                 getCurrentIconId(), contentDescription);
383 
384         int qsTypeIcon = 0;
385         IconState qsIcon = null;
386         CharSequence description = null;
387         // Only send data sim callbacks to QS.
388         if (mCurrentState.dataSim) {
389             qsTypeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.mQsDataType : 0;
390             qsIcon = new IconState(mCurrentState.enabled
391                     && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
392             description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
393         }
394         boolean activityIn = mCurrentState.dataConnected
395                 && !mCurrentState.carrierNetworkChangeMode
396                 && mCurrentState.activityIn;
397         boolean activityOut = mCurrentState.dataConnected
398                 && !mCurrentState.carrierNetworkChangeMode
399                 && mCurrentState.activityOut;
400         showDataIcon &= mCurrentState.isDefault || dataDisabled;
401         int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.mDataType : 0;
402         callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
403                 activityIn, activityOut, dataContentDescription, dataContentDescriptionHtml,
404                 description, icons.mIsWide, mSubscriptionInfo.getSubscriptionId(),
405                 mCurrentState.roaming);
406     }
407 
408     @Override
cleanState()409     protected MobileState cleanState() {
410         return new MobileState();
411     }
412 
isCdma()413     private boolean isCdma() {
414         return (mSignalStrength != null) && !mSignalStrength.isGsm();
415     }
416 
isEmergencyOnly()417     public boolean isEmergencyOnly() {
418         return (mServiceState != null && mServiceState.isEmergencyOnly());
419     }
420 
isInService()421     public boolean isInService() {
422         return Utils.isInService(mServiceState);
423     }
424 
isRoaming()425     private boolean isRoaming() {
426         // During a carrier change, roaming indications need to be supressed.
427         if (isCarrierNetworkChangeActive()) {
428             return false;
429         }
430         if (isCdma() && mServiceState != null) {
431             final int iconMode = mPhone.getCdmaEriInformation().getEriIconMode();
432             return mPhone.getCdmaEriInformation().getEriIconIndex() != CdmaEriInformation.ERI_OFF
433                     && (iconMode == CdmaEriInformation.ERI_ICON_MODE_NORMAL
434                     || iconMode == CdmaEriInformation.ERI_ICON_MODE_FLASH);
435         } else {
436             return mServiceState != null && mServiceState.getRoaming();
437         }
438     }
439 
isCarrierNetworkChangeActive()440     private boolean isCarrierNetworkChangeActive() {
441         return mCurrentState.carrierNetworkChangeMode;
442     }
443 
handleBroadcast(Intent intent)444     public void handleBroadcast(Intent intent) {
445         String action = intent.getAction();
446         if (action.equals(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)) {
447             updateNetworkName(intent.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false),
448                     intent.getStringExtra(TelephonyManager.EXTRA_SPN),
449                     intent.getStringExtra(TelephonyManager.EXTRA_DATA_SPN),
450                     intent.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false),
451                     intent.getStringExtra(TelephonyManager.EXTRA_PLMN));
452             notifyListenersIfNecessary();
453         } else if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
454             updateDataSim();
455             notifyListenersIfNecessary();
456         }
457     }
458 
updateDataSim()459     private void updateDataSim() {
460         int activeDataSubId = mDefaults.getActiveDataSubId();
461         if (SubscriptionManager.isValidSubscriptionId(activeDataSubId)) {
462             mCurrentState.dataSim = activeDataSubId == mSubscriptionInfo.getSubscriptionId();
463         } else {
464             // There doesn't seem to be a data sim selected, however if
465             // there isn't a MobileSignalController with dataSim set, then
466             // QS won't get any callbacks and will be blank.  Instead
467             // lets just assume we are the data sim (which will basically
468             // show one at random) in QS until one is selected.  The user
469             // should pick one soon after, so we shouldn't be in this state
470             // for long.
471             mCurrentState.dataSim = true;
472         }
473     }
474 
475     /**
476      * Updates the network's name based on incoming spn and plmn.
477      */
updateNetworkName(boolean showSpn, String spn, String dataSpn, boolean showPlmn, String plmn)478     void updateNetworkName(boolean showSpn, String spn, String dataSpn,
479             boolean showPlmn, String plmn) {
480         if (CHATTY) {
481             Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn
482                     + " spn=" + spn + " dataSpn=" + dataSpn
483                     + " showPlmn=" + showPlmn + " plmn=" + plmn);
484         }
485         StringBuilder str = new StringBuilder();
486         StringBuilder strData = new StringBuilder();
487         if (showPlmn && plmn != null) {
488             str.append(plmn);
489             strData.append(plmn);
490         }
491         if (showSpn && spn != null) {
492             if (str.length() != 0) {
493                 str.append(mNetworkNameSeparator);
494             }
495             str.append(spn);
496         }
497         if (str.length() != 0) {
498             mCurrentState.networkName = str.toString();
499         } else {
500             mCurrentState.networkName = mNetworkNameDefault;
501         }
502         if (showSpn && dataSpn != null) {
503             if (strData.length() != 0) {
504                 strData.append(mNetworkNameSeparator);
505             }
506             strData.append(dataSpn);
507         }
508         if (strData.length() != 0) {
509             mCurrentState.networkNameData = strData.toString();
510         } else {
511             mCurrentState.networkNameData = mNetworkNameDefault;
512         }
513     }
514 
515     /**
516      * Extracts the CellSignalStrengthCdma from SignalStrength then returns the level
517      */
getCdmaLevel()518     private final int getCdmaLevel() {
519         List<CellSignalStrengthCdma> signalStrengthCdma =
520             mSignalStrength.getCellSignalStrengths(CellSignalStrengthCdma.class);
521         if (!signalStrengthCdma.isEmpty()) {
522             return signalStrengthCdma.get(0).getLevel();
523         }
524         return CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
525     }
526 
527     /**
528      * Updates the current state based on mServiceState, mSignalStrength, mDataState,
529      * mTelephonyDisplayInfo, and mSimState.  It should be called any time one of these is updated.
530      * This will call listeners if necessary.
531      */
updateTelephony()532     private final void updateTelephony() {
533         if (DEBUG) {
534             Log.d(mTag, "updateTelephonySignalStrength: hasService=" +
535                     Utils.isInService(mServiceState) + " ss=" + mSignalStrength
536                     + " displayInfo=" + mTelephonyDisplayInfo);
537         }
538         checkDefaultData();
539         mCurrentState.connected = Utils.isInService(mServiceState) && mSignalStrength != null;
540         if (mCurrentState.connected) {
541             if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
542                 mCurrentState.level = getCdmaLevel();
543             } else {
544                 mCurrentState.level = mSignalStrength.getLevel();
545             }
546         }
547 
548         String iconKey = getIconKey();
549         if (mNetworkToIconLookup.get(iconKey) != null) {
550             mCurrentState.iconGroup = mNetworkToIconLookup.get(iconKey);
551         } else {
552             mCurrentState.iconGroup = mDefaultIcons;
553         }
554         mCurrentState.dataConnected = mCurrentState.connected
555                 && mDataState == TelephonyManager.DATA_CONNECTED;
556 
557         mCurrentState.roaming = isRoaming();
558         if (isCarrierNetworkChangeActive()) {
559             mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
560         } else if (isDataDisabled() && !mConfig.alwaysShowDataRatIcon) {
561             if (mSubscriptionInfo.getSubscriptionId() != mDefaults.getDefaultDataSubId()) {
562                 mCurrentState.iconGroup = TelephonyIcons.NOT_DEFAULT_DATA;
563             } else {
564                 mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
565             }
566         }
567         if (isEmergencyOnly() != mCurrentState.isEmergency) {
568             mCurrentState.isEmergency = isEmergencyOnly();
569             mNetworkController.recalculateEmergency();
570         }
571         // Fill in the network name if we think we have it.
572         if (mCurrentState.networkName.equals(mNetworkNameDefault) && mServiceState != null
573                 && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
574             mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
575         }
576         // If this is the data subscription, update the currentState data name
577         if (mCurrentState.networkNameData.equals(mNetworkNameDefault) && mServiceState != null
578                 && mCurrentState.dataSim
579                 && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
580             mCurrentState.networkNameData = mServiceState.getOperatorAlphaShort();
581         }
582 
583         notifyListenersIfNecessary();
584     }
585 
586     /**
587      * If we are controlling the NOT_DEFAULT_DATA icon, check the status of the other one
588      */
checkDefaultData()589     private void checkDefaultData() {
590         if (mCurrentState.iconGroup != TelephonyIcons.NOT_DEFAULT_DATA) {
591             mCurrentState.defaultDataOff = false;
592             return;
593         }
594 
595         mCurrentState.defaultDataOff = mNetworkController.isDataControllerDisabled();
596     }
597 
onMobileDataChanged()598     void onMobileDataChanged() {
599         checkDefaultData();
600         notifyListenersIfNecessary();
601     }
602 
isDataDisabled()603     boolean isDataDisabled() {
604         return !mPhone.isDataConnectionAllowed();
605     }
606 
607     @VisibleForTesting
setActivity(int activity)608     void setActivity(int activity) {
609         mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
610                 || activity == TelephonyManager.DATA_ACTIVITY_IN;
611         mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
612                 || activity == TelephonyManager.DATA_ACTIVITY_OUT;
613         notifyListenersIfNecessary();
614     }
615 
616     @Override
dump(PrintWriter pw)617     public void dump(PrintWriter pw) {
618         super.dump(pw);
619         pw.println("  mSubscription=" + mSubscriptionInfo + ",");
620         pw.println("  mServiceState=" + mServiceState + ",");
621         pw.println("  mSignalStrength=" + mSignalStrength + ",");
622         pw.println("  mTelephonyDisplayInfo=" + mTelephonyDisplayInfo + ",");
623         pw.println("  mDataState=" + mDataState + ",");
624         pw.println("  mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
625         pw.println("  isDataDisabled=" + isDataDisabled() + ",");
626     }
627 
628     class MobilePhoneStateListener extends PhoneStateListener {
MobilePhoneStateListener(Executor executor)629         public MobilePhoneStateListener(Executor executor) {
630             super(executor);
631         }
632 
633         @Override
onSignalStrengthsChanged(SignalStrength signalStrength)634         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
635             if (DEBUG) {
636                 Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength +
637                         ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
638             }
639             mSignalStrength = signalStrength;
640             updateTelephony();
641         }
642 
643         @Override
onServiceStateChanged(ServiceState state)644         public void onServiceStateChanged(ServiceState state) {
645             if (DEBUG) {
646                 Log.d(mTag, "onServiceStateChanged voiceState=" + state.getState()
647                         + " dataState=" + state.getDataRegistrationState());
648             }
649             mServiceState = state;
650             updateTelephony();
651         }
652 
653         @Override
onDataConnectionStateChanged(int state, int networkType)654         public void onDataConnectionStateChanged(int state, int networkType) {
655             if (DEBUG) {
656                 Log.d(mTag, "onDataConnectionStateChanged: state=" + state
657                         + " type=" + networkType);
658             }
659             mDataState = state;
660             updateTelephony();
661         }
662 
663         @Override
onDataActivity(int direction)664         public void onDataActivity(int direction) {
665             if (DEBUG) {
666                 Log.d(mTag, "onDataActivity: direction=" + direction);
667             }
668             setActivity(direction);
669         }
670 
671         @Override
onCarrierNetworkChange(boolean active)672         public void onCarrierNetworkChange(boolean active) {
673             if (DEBUG) {
674                 Log.d(mTag, "onCarrierNetworkChange: active=" + active);
675             }
676             mCurrentState.carrierNetworkChangeMode = active;
677             updateTelephony();
678         }
679 
680         @Override
onActiveDataSubscriptionIdChanged(int subId)681         public void onActiveDataSubscriptionIdChanged(int subId) {
682             if (DEBUG) Log.d(mTag, "onActiveDataSubscriptionIdChanged: subId=" + subId);
683             updateDataSim();
684             updateTelephony();
685         }
686 
687         @Override
onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo)688         public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) {
689             if (DEBUG) {
690                 Log.d(mTag, "onDisplayInfoChanged: telephonyDisplayInfo=" + telephonyDisplayInfo);
691             }
692             mTelephonyDisplayInfo = telephonyDisplayInfo;
693             updateTelephony();
694         }
695     }
696 
697     static class MobileIconGroup extends SignalController.IconGroup {
698         final int mDataContentDescription; // mContentDescriptionDataType
699         final int mDataType;
700         final boolean mIsWide;
701         final int mQsDataType;
702 
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)703         public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
704                 int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
705                 int discContentDesc, int dataContentDesc, int dataType, boolean isWide) {
706             super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
707                     qsDiscState, discContentDesc);
708             mDataContentDescription = dataContentDesc;
709             mDataType = dataType;
710             mIsWide = isWide;
711             mQsDataType = dataType; // TODO: remove this field
712         }
713     }
714 
715     static class MobileState extends SignalController.State {
716         String networkName;
717         String networkNameData;
718         boolean dataSim;
719         boolean dataConnected;
720         boolean isEmergency;
721         boolean airplaneMode;
722         boolean carrierNetworkChangeMode;
723         boolean isDefault;
724         boolean userSetup;
725         boolean roaming;
726         boolean defaultDataOff;  // Tracks the on/off state of the defaultDataSubscription
727 
728         @Override
copyFrom(State s)729         public void copyFrom(State s) {
730             super.copyFrom(s);
731             MobileState state = (MobileState) s;
732             dataSim = state.dataSim;
733             networkName = state.networkName;
734             networkNameData = state.networkNameData;
735             dataConnected = state.dataConnected;
736             isDefault = state.isDefault;
737             isEmergency = state.isEmergency;
738             airplaneMode = state.airplaneMode;
739             carrierNetworkChangeMode = state.carrierNetworkChangeMode;
740             userSetup = state.userSetup;
741             roaming = state.roaming;
742             defaultDataOff = state.defaultDataOff;
743         }
744 
745         @Override
toString(StringBuilder builder)746         protected void toString(StringBuilder builder) {
747             super.toString(builder);
748             builder.append(',');
749             builder.append("dataSim=").append(dataSim).append(',');
750             builder.append("networkName=").append(networkName).append(',');
751             builder.append("networkNameData=").append(networkNameData).append(',');
752             builder.append("dataConnected=").append(dataConnected).append(',');
753             builder.append("roaming=").append(roaming).append(',');
754             builder.append("isDefault=").append(isDefault).append(',');
755             builder.append("isEmergency=").append(isEmergency).append(',');
756             builder.append("airplaneMode=").append(airplaneMode).append(',');
757             builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode)
758                     .append(',');
759             builder.append("userSetup=").append(userSetup).append(',');
760             builder.append("defaultDataOff=").append(defaultDataOff);
761         }
762 
763         @Override
equals(Object o)764         public boolean equals(Object o) {
765             return super.equals(o)
766                     && Objects.equals(((MobileState) o).networkName, networkName)
767                     && Objects.equals(((MobileState) o).networkNameData, networkNameData)
768                     && ((MobileState) o).dataSim == dataSim
769                     && ((MobileState) o).dataConnected == dataConnected
770                     && ((MobileState) o).isEmergency == isEmergency
771                     && ((MobileState) o).airplaneMode == airplaneMode
772                     && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
773                     && ((MobileState) o).userSetup == userSetup
774                     && ((MobileState) o).isDefault == isDefault
775                     && ((MobileState) o).roaming == roaming
776                     && ((MobileState) o).defaultDataOff == defaultDataOff;
777         }
778     }
779 }
780