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