• 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.net.NetworkCapabilities;
21 import android.os.Looper;
22 import android.telephony.PhoneStateListener;
23 import android.telephony.ServiceState;
24 import android.telephony.SignalStrength;
25 import android.telephony.SubscriptionInfo;
26 import android.telephony.SubscriptionManager;
27 import android.telephony.TelephonyManager;
28 import android.text.TextUtils;
29 import android.util.Log;
30 import android.util.SparseArray;
31 
32 import com.android.internal.annotations.VisibleForTesting;
33 import com.android.internal.telephony.TelephonyIntents;
34 import com.android.internal.telephony.cdma.EriInfo;
35 import com.android.systemui.R;
36 import com.android.systemui.statusbar.policy.NetworkController.IconState;
37 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
38 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
39 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
40 
41 import java.io.PrintWriter;
42 import java.util.BitSet;
43 import java.util.Objects;
44 
45 
46 public class MobileSignalController extends SignalController<
47         MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> {
48     private final TelephonyManager mPhone;
49     private final SubscriptionDefaults mDefaults;
50     private final String mNetworkNameDefault;
51     private final String mNetworkNameSeparator;
52     @VisibleForTesting
53     final PhoneStateListener mPhoneStateListener;
54     // Save entire info for logging, we only use the id.
55     final SubscriptionInfo mSubscriptionInfo;
56 
57     // @VisibleForDemoMode
58     final SparseArray<MobileIconGroup> mNetworkToIconLookup;
59 
60     // Since some pieces of the phone state are interdependent we store it locally,
61     // this could potentially become part of MobileState for simplification/complication
62     // of code.
63     private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
64     private int mDataState = TelephonyManager.DATA_DISCONNECTED;
65     private ServiceState mServiceState;
66     private SignalStrength mSignalStrength;
67     private MobileIconGroup mDefaultIcons;
68     private Config mConfig;
69 
70     // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
71     // need listener lists anymore.
MobileSignalController(Context context, Config config, boolean hasMobileData, TelephonyManager phone, CallbackHandler callbackHandler, NetworkControllerImpl networkController, SubscriptionInfo info, SubscriptionDefaults defaults, Looper receiverLooper)72     public MobileSignalController(Context context, Config config, boolean hasMobileData,
73             TelephonyManager phone, CallbackHandler callbackHandler,
74             NetworkControllerImpl networkController, SubscriptionInfo info,
75             SubscriptionDefaults defaults, Looper receiverLooper) {
76         super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
77                 NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
78                 networkController);
79         mNetworkToIconLookup = new SparseArray<>();
80         mConfig = config;
81         mPhone = phone;
82         mDefaults = defaults;
83         mSubscriptionInfo = info;
84         mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(),
85                 receiverLooper);
86         mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
87         mNetworkNameDefault = getStringIfExists(
88                 com.android.internal.R.string.lockscreen_carrier_default);
89 
90         mapIconSets();
91 
92         String networkName = info.getCarrierName() != null ? info.getCarrierName().toString()
93                 : mNetworkNameDefault;
94         mLastState.networkName = mCurrentState.networkName = networkName;
95         mLastState.networkNameData = mCurrentState.networkNameData = networkName;
96         mLastState.enabled = mCurrentState.enabled = hasMobileData;
97         mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
98         // Get initial data sim state.
99         updateDataSim();
100     }
101 
setConfiguration(Config config)102     public void setConfiguration(Config config) {
103         mConfig = config;
104         mapIconSets();
105         updateTelephony();
106     }
107 
getDataContentDescription()108     public int getDataContentDescription() {
109         return getIcons().mDataContentDescription;
110     }
111 
setAirplaneMode(boolean airplaneMode)112     public void setAirplaneMode(boolean airplaneMode) {
113         mCurrentState.airplaneMode = airplaneMode;
114         notifyListenersIfNecessary();
115     }
116 
setUserSetupComplete(boolean userSetup)117     public void setUserSetupComplete(boolean userSetup) {
118         mCurrentState.userSetup = userSetup;
119         notifyListenersIfNecessary();
120     }
121 
122     @Override
updateConnectivity(BitSet connectedTransports, BitSet validatedTransports)123     public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
124         boolean isValidated = validatedTransports.get(mTransportType);
125         mCurrentState.isDefault = connectedTransports.get(mTransportType);
126         // Only show this as not having connectivity if we are default.
127         mCurrentState.inetCondition = (isValidated || !mCurrentState.isDefault) ? 1 : 0;
128         notifyListenersIfNecessary();
129     }
130 
setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode)131     public void setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode) {
132         mCurrentState.carrierNetworkChangeMode = carrierNetworkChangeMode;
133         updateTelephony();
134     }
135 
136     /**
137      * Start listening for phone state changes.
138      */
registerListener()139     public void registerListener() {
140         mPhone.listen(mPhoneStateListener,
141                 PhoneStateListener.LISTEN_SERVICE_STATE
142                         | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
143                         | PhoneStateListener.LISTEN_CALL_STATE
144                         | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
145                         | PhoneStateListener.LISTEN_DATA_ACTIVITY
146                         | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
147     }
148 
149     /**
150      * Stop listening for phone state changes.
151      */
unregisterListener()152     public void unregisterListener() {
153         mPhone.listen(mPhoneStateListener, 0);
154     }
155 
156     /**
157      * Produce a mapping of data network types to icon groups for simple and quick use in
158      * updateTelephony.
159      */
mapIconSets()160     private void mapIconSets() {
161         mNetworkToIconLookup.clear();
162 
163         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G);
164         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G);
165         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G);
166         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
167         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
168 
169         if (!mConfig.showAtLeast3G) {
170             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
171                     TelephonyIcons.UNKNOWN);
172             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E);
173             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X);
174             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X);
175 
176             mDefaultIcons = TelephonyIcons.G;
177         } else {
178             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
179                     TelephonyIcons.THREE_G);
180             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE,
181                     TelephonyIcons.THREE_G);
182             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA,
183                     TelephonyIcons.THREE_G);
184             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT,
185                     TelephonyIcons.THREE_G);
186             mDefaultIcons = TelephonyIcons.THREE_G;
187         }
188 
189         MobileIconGroup hGroup = TelephonyIcons.THREE_G;
190         if (mConfig.hspaDataDistinguishable) {
191             hGroup = TelephonyIcons.H;
192         }
193         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
194         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
195         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
196         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup);
197 
198         if (mConfig.show4gForLte) {
199             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
200             if (mConfig.hideLtePlus) {
201                 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
202                         TelephonyIcons.FOUR_G);
203             } else {
204                 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
205                         TelephonyIcons.FOUR_G_PLUS);
206             }
207         } else {
208             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
209             if (mConfig.hideLtePlus) {
210                 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
211                         TelephonyIcons.LTE);
212             } else {
213                 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
214                         TelephonyIcons.LTE_PLUS);
215             }
216         }
217         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
218     }
219 
220     @Override
notifyListeners(SignalCallback callback)221     public void notifyListeners(SignalCallback callback) {
222         MobileIconGroup icons = getIcons();
223 
224         String contentDescription = getStringIfExists(getContentDescription());
225         String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
226         final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
227                 && mCurrentState.userSetup;
228 
229         // Show icon in QS when we are connected or need to show roaming or data is disabled.
230         boolean showDataIcon = mCurrentState.dataConnected
231                 || mCurrentState.iconGroup == TelephonyIcons.ROAMING
232                 || dataDisabled;
233         IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
234                 getCurrentIconId(), contentDescription);
235 
236         int qsTypeIcon = 0;
237         IconState qsIcon = null;
238         String description = null;
239         // Only send data sim callbacks to QS.
240         if (mCurrentState.dataSim) {
241             qsTypeIcon = showDataIcon ? icons.mQsDataType : 0;
242             qsIcon = new IconState(mCurrentState.enabled
243                     && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
244             description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
245         }
246         boolean activityIn = mCurrentState.dataConnected
247                         && !mCurrentState.carrierNetworkChangeMode
248                         && mCurrentState.activityIn;
249         boolean activityOut = mCurrentState.dataConnected
250                         && !mCurrentState.carrierNetworkChangeMode
251                         && mCurrentState.activityOut;
252         showDataIcon &= mCurrentState.isDefault
253                 || mCurrentState.iconGroup == TelephonyIcons.ROAMING
254                 || dataDisabled;
255         int typeIcon = showDataIcon ? icons.mDataType : 0;
256         callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
257                 activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
258                 mSubscriptionInfo.getSubscriptionId());
259     }
260 
261     @Override
cleanState()262     protected MobileState cleanState() {
263         return new MobileState();
264     }
265 
hasService()266     private boolean hasService() {
267         if (mServiceState != null) {
268             // Consider the device to be in service if either voice or data
269             // service is available. Some SIM cards are marketed as data-only
270             // and do not support voice service, and on these SIM cards, we
271             // want to show signal bars for data service as well as the "no
272             // service" or "emergency calls only" text that indicates that voice
273             // is not available.
274             switch (mServiceState.getVoiceRegState()) {
275                 case ServiceState.STATE_POWER_OFF:
276                     return false;
277                 case ServiceState.STATE_OUT_OF_SERVICE:
278                 case ServiceState.STATE_EMERGENCY_ONLY:
279                     return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
280                 default:
281                     return true;
282             }
283         } else {
284             return false;
285         }
286     }
287 
isCdma()288     private boolean isCdma() {
289         return (mSignalStrength != null) && !mSignalStrength.isGsm();
290     }
291 
isEmergencyOnly()292     public boolean isEmergencyOnly() {
293         return (mServiceState != null && mServiceState.isEmergencyOnly());
294     }
295 
isRoaming()296     private boolean isRoaming() {
297         if (isCdma()) {
298             final int iconMode = mServiceState.getCdmaEriIconMode();
299             return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
300                     && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
301                         || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
302         } else {
303             return mServiceState != null && mServiceState.getRoaming();
304         }
305     }
306 
isCarrierNetworkChangeActive()307     private boolean isCarrierNetworkChangeActive() {
308         return mCurrentState.carrierNetworkChangeMode;
309     }
310 
handleBroadcast(Intent intent)311     public void handleBroadcast(Intent intent) {
312         String action = intent.getAction();
313         if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
314             updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
315                     intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
316                     intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN),
317                     intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
318                     intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
319             notifyListenersIfNecessary();
320         } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
321             updateDataSim();
322             notifyListenersIfNecessary();
323         }
324     }
325 
updateDataSim()326     private void updateDataSim() {
327         int defaultDataSub = mDefaults.getDefaultDataSubId();
328         if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) {
329             mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId();
330         } else {
331             // There doesn't seem to be a data sim selected, however if
332             // there isn't a MobileSignalController with dataSim set, then
333             // QS won't get any callbacks and will be blank.  Instead
334             // lets just assume we are the data sim (which will basically
335             // show one at random) in QS until one is selected.  The user
336             // should pick one soon after, so we shouldn't be in this state
337             // for long.
338             mCurrentState.dataSim = true;
339         }
340     }
341 
342     /**
343      * Updates the network's name based on incoming spn and plmn.
344      */
updateNetworkName(boolean showSpn, String spn, String dataSpn, boolean showPlmn, String plmn)345     void updateNetworkName(boolean showSpn, String spn, String dataSpn,
346             boolean showPlmn, String plmn) {
347         if (CHATTY) {
348             Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn
349                     + " spn=" + spn + " dataSpn=" + dataSpn
350                     + " showPlmn=" + showPlmn + " plmn=" + plmn);
351         }
352         StringBuilder str = new StringBuilder();
353         StringBuilder strData = new StringBuilder();
354         if (showPlmn && plmn != null) {
355             str.append(plmn);
356             strData.append(plmn);
357         }
358         if (showSpn && spn != null) {
359             if (str.length() != 0) {
360                 str.append(mNetworkNameSeparator);
361             }
362             str.append(spn);
363         }
364         if (str.length() != 0) {
365             mCurrentState.networkName = str.toString();
366         } else {
367             mCurrentState.networkName = mNetworkNameDefault;
368         }
369         if (showSpn && dataSpn != null) {
370             if (strData.length() != 0) {
371                 strData.append(mNetworkNameSeparator);
372             }
373             strData.append(dataSpn);
374         }
375         if (strData.length() != 0) {
376             mCurrentState.networkNameData = strData.toString();
377         } else {
378             mCurrentState.networkNameData = mNetworkNameDefault;
379         }
380     }
381 
382     /**
383      * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
384      * mDataState, and mSimState.  It should be called any time one of these is updated.
385      * This will call listeners if necessary.
386      */
updateTelephony()387     private final void updateTelephony() {
388         if (DEBUG) {
389             Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService()
390                     + " ss=" + mSignalStrength);
391         }
392         mCurrentState.connected = hasService() && mSignalStrength != null;
393         if (mCurrentState.connected) {
394             if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
395                 mCurrentState.level = mSignalStrength.getCdmaLevel();
396             } else {
397                 mCurrentState.level = mSignalStrength.getLevel();
398             }
399         }
400         if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
401             mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
402         } else {
403             mCurrentState.iconGroup = mDefaultIcons;
404         }
405         mCurrentState.dataConnected = mCurrentState.connected
406                 && mDataState == TelephonyManager.DATA_CONNECTED;
407 
408         if (isCarrierNetworkChangeActive()) {
409             mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
410         } else if (isRoaming()) {
411             mCurrentState.iconGroup = TelephonyIcons.ROAMING;
412         } else if (isDataDisabled()) {
413             mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
414         }
415         if (isEmergencyOnly() != mCurrentState.isEmergency) {
416             mCurrentState.isEmergency = isEmergencyOnly();
417             mNetworkController.recalculateEmergency();
418         }
419         // Fill in the network name if we think we have it.
420         if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null
421                 && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
422             mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
423         }
424 
425         notifyListenersIfNecessary();
426     }
427 
isDataDisabled()428     private boolean isDataDisabled() {
429         return !mPhone.getDataEnabled(mSubscriptionInfo.getSubscriptionId());
430     }
431 
432     @VisibleForTesting
setActivity(int activity)433     void setActivity(int activity) {
434         mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
435                 || activity == TelephonyManager.DATA_ACTIVITY_IN;
436         mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
437                 || activity == TelephonyManager.DATA_ACTIVITY_OUT;
438         notifyListenersIfNecessary();
439     }
440 
441     @Override
dump(PrintWriter pw)442     public void dump(PrintWriter pw) {
443         super.dump(pw);
444         pw.println("  mSubscription=" + mSubscriptionInfo + ",");
445         pw.println("  mServiceState=" + mServiceState + ",");
446         pw.println("  mSignalStrength=" + mSignalStrength + ",");
447         pw.println("  mDataState=" + mDataState + ",");
448         pw.println("  mDataNetType=" + mDataNetType + ",");
449     }
450 
451     class MobilePhoneStateListener extends PhoneStateListener {
MobilePhoneStateListener(int subId, Looper looper)452         public MobilePhoneStateListener(int subId, Looper looper) {
453             super(subId, looper);
454         }
455 
456         @Override
onSignalStrengthsChanged(SignalStrength signalStrength)457         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
458             if (DEBUG) {
459                 Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength +
460                         ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
461             }
462             mSignalStrength = signalStrength;
463             updateTelephony();
464         }
465 
466         @Override
onServiceStateChanged(ServiceState state)467         public void onServiceStateChanged(ServiceState state) {
468             if (DEBUG) {
469                 Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
470                         + " dataState=" + state.getDataRegState());
471             }
472             mServiceState = state;
473             mDataNetType = state.getDataNetworkType();
474             if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
475                     mServiceState.isUsingCarrierAggregation()) {
476                 mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
477             }
478             updateTelephony();
479         }
480 
481         @Override
onDataConnectionStateChanged(int state, int networkType)482         public void onDataConnectionStateChanged(int state, int networkType) {
483             if (DEBUG) {
484                 Log.d(mTag, "onDataConnectionStateChanged: state=" + state
485                         + " type=" + networkType);
486             }
487             mDataState = state;
488             mDataNetType = networkType;
489             if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
490                     mServiceState.isUsingCarrierAggregation()) {
491                 mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
492             }
493             updateTelephony();
494         }
495 
496         @Override
onDataActivity(int direction)497         public void onDataActivity(int direction) {
498             if (DEBUG) {
499                 Log.d(mTag, "onDataActivity: direction=" + direction);
500             }
501             setActivity(direction);
502         }
503 
504         @Override
onCarrierNetworkChange(boolean active)505         public void onCarrierNetworkChange(boolean active) {
506             if (DEBUG) {
507                 Log.d(mTag, "onCarrierNetworkChange: active=" + active);
508             }
509             mCurrentState.carrierNetworkChangeMode = active;
510 
511             updateTelephony();
512         }
513     };
514 
515     static class MobileIconGroup extends SignalController.IconGroup {
516         final int mDataContentDescription; // mContentDescriptionDataType
517         final int mDataType;
518         final boolean mIsWide;
519         final int mQsDataType;
520 
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, int qsDataType)521         public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
522                 int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
523                 int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
524                 int qsDataType) {
525             super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
526                     qsDiscState, discContentDesc);
527             mDataContentDescription = dataContentDesc;
528             mDataType = dataType;
529             mIsWide = isWide;
530             mQsDataType = qsDataType;
531         }
532     }
533 
534     static class MobileState extends SignalController.State {
535         String networkName;
536         String networkNameData;
537         boolean dataSim;
538         boolean dataConnected;
539         boolean isEmergency;
540         boolean airplaneMode;
541         boolean carrierNetworkChangeMode;
542         boolean isDefault;
543         boolean userSetup;
544 
545         @Override
copyFrom(State s)546         public void copyFrom(State s) {
547             super.copyFrom(s);
548             MobileState state = (MobileState) s;
549             dataSim = state.dataSim;
550             networkName = state.networkName;
551             networkNameData = state.networkNameData;
552             dataConnected = state.dataConnected;
553             isDefault = state.isDefault;
554             isEmergency = state.isEmergency;
555             airplaneMode = state.airplaneMode;
556             carrierNetworkChangeMode = state.carrierNetworkChangeMode;
557             userSetup = state.userSetup;
558         }
559 
560         @Override
toString(StringBuilder builder)561         protected void toString(StringBuilder builder) {
562             super.toString(builder);
563             builder.append(',');
564             builder.append("dataSim=").append(dataSim).append(',');
565             builder.append("networkName=").append(networkName).append(',');
566             builder.append("networkNameData=").append(networkNameData).append(',');
567             builder.append("dataConnected=").append(dataConnected).append(',');
568             builder.append("isDefault=").append(isDefault).append(',');
569             builder.append("isEmergency=").append(isEmergency).append(',');
570             builder.append("airplaneMode=").append(airplaneMode).append(',');
571             builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode)
572                     .append(',');
573             builder.append("userSetup=").append(userSetup);
574         }
575 
576         @Override
equals(Object o)577         public boolean equals(Object o) {
578             return super.equals(o)
579                     && Objects.equals(((MobileState) o).networkName, networkName)
580                     && Objects.equals(((MobileState) o).networkNameData, networkNameData)
581                     && ((MobileState) o).dataSim == dataSim
582                     && ((MobileState) o).dataConnected == dataConnected
583                     && ((MobileState) o).isEmergency == isEmergency
584                     && ((MobileState) o).airplaneMode == airplaneMode
585                     && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
586                     && ((MobileState) o).userSetup == userSetup
587                     && ((MobileState) o).isDefault == isDefault;
588         }
589     }
590 }
591