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