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         return SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
    239     }
    240 
    241     @Override
    242     public int getCurrentIconId() {
    243         if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) {
    244             return SignalDrawable.getCarrierChangeState(getNumLevels());
    245         } else if (mCurrentState.connected) {
    246             return SignalDrawable.getState(mCurrentState.level, getNumLevels(),
    247                     mCurrentState.inetCondition == 0);
    248         } else if (mCurrentState.enabled) {
    249             return SignalDrawable.getEmptyState(getNumLevels());
    250         } else {
    251             return 0;
    252         }
    253     }
    254 
    255     @Override
    256     public int getQsCurrentIconId() {
    257         if (mCurrentState.airplaneMode) {
    258             return SignalDrawable.getAirplaneModeState(getNumLevels());
    259         }
    260 
    261         return getCurrentIconId();
    262     }
    263 
    264     @Override
    265     public void notifyListeners(SignalCallback callback) {
    266         MobileIconGroup icons = getIcons();
    267 
    268         String contentDescription = getStringIfExists(getContentDescription());
    269         String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
    270         final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
    271                 && mCurrentState.userSetup;
    272 
    273         // Show icon in QS when we are connected or data is disabled.
    274         boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
    275         IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
    276                 getCurrentIconId(), contentDescription);
    277 
    278         int qsTypeIcon = 0;
    279         IconState qsIcon = null;
    280         String description = null;
    281         // Only send data sim callbacks to QS.
    282         if (mCurrentState.dataSim) {
    283             qsTypeIcon = showDataIcon ? icons.mQsDataType : 0;
    284             qsIcon = new IconState(mCurrentState.enabled
    285                     && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
    286             description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
    287         }
    288         boolean activityIn = mCurrentState.dataConnected
    289                 && !mCurrentState.carrierNetworkChangeMode
    290                 && mCurrentState.activityIn;
    291         boolean activityOut = mCurrentState.dataConnected
    292                 && !mCurrentState.carrierNetworkChangeMode
    293                 && mCurrentState.activityOut;
    294         showDataIcon &= mCurrentState.isDefault || dataDisabled;
    295         int typeIcon = showDataIcon ? icons.mDataType : 0;
    296         callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
    297                 activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
    298                 mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);
    299     }
    300 
    301     @Override
    302     protected MobileState cleanState() {
    303         return new MobileState();
    304     }
    305 
    306     private boolean hasService() {
    307         if (mServiceState != null) {
    308             // Consider the device to be in service if either voice or data
    309             // service is available. Some SIM cards are marketed as data-only
    310             // and do not support voice service, and on these SIM cards, we
    311             // want to show signal bars for data service as well as the "no
    312             // service" or "emergency calls only" text that indicates that voice
    313             // is not available.
    314             switch (mServiceState.getVoiceRegState()) {
    315                 case ServiceState.STATE_POWER_OFF:
    316                     return false;
    317                 case ServiceState.STATE_OUT_OF_SERVICE:
    318                 case ServiceState.STATE_EMERGENCY_ONLY:
    319                     return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
    320                 default:
    321                     return true;
    322             }
    323         } else {
    324             return false;
    325         }
    326     }
    327 
    328     private boolean isCdma() {
    329         return (mSignalStrength != null) && !mSignalStrength.isGsm();
    330     }
    331 
    332     public boolean isEmergencyOnly() {
    333         return (mServiceState != null && mServiceState.isEmergencyOnly());
    334     }
    335 
    336     private boolean isRoaming() {
    337         // During a carrier change, roaming indications need to be supressed.
    338         if (isCarrierNetworkChangeActive()) {
    339             return false;
    340         }
    341         if (isCdma()) {
    342             final int iconMode = mServiceState.getCdmaEriIconMode();
    343             return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
    344                     && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
    345                     || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
    346         } else {
    347             return mServiceState != null && mServiceState.getRoaming();
    348         }
    349     }
    350 
    351     private boolean isCarrierNetworkChangeActive() {
    352         return mCurrentState.carrierNetworkChangeMode;
    353     }
    354 
    355     public void handleBroadcast(Intent intent) {
    356         String action = intent.getAction();
    357         if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
    358             updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
    359                     intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
    360                     intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN),
    361                     intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
    362                     intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
    363             notifyListenersIfNecessary();
    364         } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
    365             updateDataSim();
    366             notifyListenersIfNecessary();
    367         }
    368     }
    369 
    370     private void updateDataSim() {
    371         int defaultDataSub = mDefaults.getDefaultDataSubId();
    372         if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) {
    373             mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId();
    374         } else {
    375             // There doesn't seem to be a data sim selected, however if
    376             // there isn't a MobileSignalController with dataSim set, then
    377             // QS won't get any callbacks and will be blank.  Instead
    378             // lets just assume we are the data sim (which will basically
    379             // show one at random) in QS until one is selected.  The user
    380             // should pick one soon after, so we shouldn't be in this state
    381             // for long.
    382             mCurrentState.dataSim = true;
    383         }
    384     }
    385 
    386     /**
    387      * Updates the network's name based on incoming spn and plmn.
    388      */
    389     void updateNetworkName(boolean showSpn, String spn, String dataSpn,
    390             boolean showPlmn, String plmn) {
    391         if (CHATTY) {
    392             Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn
    393                     + " spn=" + spn + " dataSpn=" + dataSpn
    394                     + " showPlmn=" + showPlmn + " plmn=" + plmn);
    395         }
    396         StringBuilder str = new StringBuilder();
    397         StringBuilder strData = new StringBuilder();
    398         if (showPlmn && plmn != null) {
    399             str.append(plmn);
    400             strData.append(plmn);
    401         }
    402         if (showSpn && spn != null) {
    403             if (str.length() != 0) {
    404                 str.append(mNetworkNameSeparator);
    405             }
    406             str.append(spn);
    407         }
    408         if (str.length() != 0) {
    409             mCurrentState.networkName = str.toString();
    410         } else {
    411             mCurrentState.networkName = mNetworkNameDefault;
    412         }
    413         if (showSpn && dataSpn != null) {
    414             if (strData.length() != 0) {
    415                 strData.append(mNetworkNameSeparator);
    416             }
    417             strData.append(dataSpn);
    418         }
    419         if (strData.length() != 0) {
    420             mCurrentState.networkNameData = strData.toString();
    421         } else {
    422             mCurrentState.networkNameData = mNetworkNameDefault;
    423         }
    424     }
    425 
    426     /**
    427      * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
    428      * mDataState, and mSimState.  It should be called any time one of these is updated.
    429      * This will call listeners if necessary.
    430      */
    431     private final void updateTelephony() {
    432         if (DEBUG) {
    433             Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService()
    434                     + " ss=" + mSignalStrength);
    435         }
    436         mCurrentState.connected = hasService() && mSignalStrength != null;
    437         if (mCurrentState.connected) {
    438             if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
    439                 mCurrentState.level = mSignalStrength.getCdmaLevel();
    440             } else {
    441                 mCurrentState.level = mSignalStrength.getLevel();
    442             }
    443         }
    444         if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
    445             mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
    446         } else {
    447             mCurrentState.iconGroup = mDefaultIcons;
    448         }
    449         mCurrentState.dataConnected = mCurrentState.connected
    450                 && mDataState == TelephonyManager.DATA_CONNECTED;
    451 
    452         mCurrentState.roaming = isRoaming();
    453         if (isCarrierNetworkChangeActive()) {
    454             mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
    455         } else if (isDataDisabled()) {
    456             mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
    457         }
    458         if (isEmergencyOnly() != mCurrentState.isEmergency) {
    459             mCurrentState.isEmergency = isEmergencyOnly();
    460             mNetworkController.recalculateEmergency();
    461         }
    462         // Fill in the network name if we think we have it.
    463         if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null
    464                 && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
    465             mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
    466         }
    467 
    468         notifyListenersIfNecessary();
    469     }
    470 
    471     private boolean isDataDisabled() {
    472         return !mPhone.getDataEnabled(mSubscriptionInfo.getSubscriptionId());
    473     }
    474 
    475     @VisibleForTesting
    476     void setActivity(int activity) {
    477         mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
    478                 || activity == TelephonyManager.DATA_ACTIVITY_IN;
    479         mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
    480                 || activity == TelephonyManager.DATA_ACTIVITY_OUT;
    481         notifyListenersIfNecessary();
    482     }
    483 
    484     @Override
    485     public void dump(PrintWriter pw) {
    486         super.dump(pw);
    487         pw.println("  mSubscription=" + mSubscriptionInfo + ",");
    488         pw.println("  mServiceState=" + mServiceState + ",");
    489         pw.println("  mSignalStrength=" + mSignalStrength + ",");
    490         pw.println("  mDataState=" + mDataState + ",");
    491         pw.println("  mDataNetType=" + mDataNetType + ",");
    492     }
    493 
    494     class MobilePhoneStateListener extends PhoneStateListener {
    495         public MobilePhoneStateListener(int subId, Looper looper) {
    496             super(subId, looper);
    497         }
    498 
    499         @Override
    500         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
    501             if (DEBUG) {
    502                 Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength +
    503                         ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
    504             }
    505             mSignalStrength = signalStrength;
    506             updateTelephony();
    507         }
    508 
    509         @Override
    510         public void onServiceStateChanged(ServiceState state) {
    511             if (DEBUG) {
    512                 Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
    513                         + " dataState=" + state.getDataRegState());
    514             }
    515             mServiceState = state;
    516             mDataNetType = state.getDataNetworkType();
    517             if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
    518                     mServiceState.isUsingCarrierAggregation()) {
    519                 mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
    520             }
    521             updateTelephony();
    522         }
    523 
    524         @Override
    525         public void onDataConnectionStateChanged(int state, int networkType) {
    526             if (DEBUG) {
    527                 Log.d(mTag, "onDataConnectionStateChanged: state=" + state
    528                         + " type=" + networkType);
    529             }
    530             mDataState = state;
    531             mDataNetType = networkType;
    532             if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
    533                     mServiceState.isUsingCarrierAggregation()) {
    534                 mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
    535             }
    536             updateTelephony();
    537         }
    538 
    539         @Override
    540         public void onDataActivity(int direction) {
    541             if (DEBUG) {
    542                 Log.d(mTag, "onDataActivity: direction=" + direction);
    543             }
    544             setActivity(direction);
    545         }
    546 
    547         @Override
    548         public void onCarrierNetworkChange(boolean active) {
    549             if (DEBUG) {
    550                 Log.d(mTag, "onCarrierNetworkChange: active=" + active);
    551             }
    552             mCurrentState.carrierNetworkChangeMode = active;
    553 
    554             updateTelephony();
    555         }
    556     };
    557 
    558     static class MobileIconGroup extends SignalController.IconGroup {
    559         final int mDataContentDescription; // mContentDescriptionDataType
    560         final int mDataType;
    561         final boolean mIsWide;
    562         final int mQsDataType;
    563 
    564         public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
    565                 int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
    566                 int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
    567                 int qsDataType) {
    568             super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
    569                     qsDiscState, discContentDesc);
    570             mDataContentDescription = dataContentDesc;
    571             mDataType = dataType;
    572             mIsWide = isWide;
    573             mQsDataType = qsDataType;
    574         }
    575     }
    576 
    577     static class MobileState extends SignalController.State {
    578         String networkName;
    579         String networkNameData;
    580         boolean dataSim;
    581         boolean dataConnected;
    582         boolean isEmergency;
    583         boolean airplaneMode;
    584         boolean carrierNetworkChangeMode;
    585         boolean isDefault;
    586         boolean userSetup;
    587         boolean roaming;
    588 
    589         @Override
    590         public void copyFrom(State s) {
    591             super.copyFrom(s);
    592             MobileState state = (MobileState) s;
    593             dataSim = state.dataSim;
    594             networkName = state.networkName;
    595             networkNameData = state.networkNameData;
    596             dataConnected = state.dataConnected;
    597             isDefault = state.isDefault;
    598             isEmergency = state.isEmergency;
    599             airplaneMode = state.airplaneMode;
    600             carrierNetworkChangeMode = state.carrierNetworkChangeMode;
    601             userSetup = state.userSetup;
    602             roaming = state.roaming;
    603         }
    604 
    605         @Override
    606         protected void toString(StringBuilder builder) {
    607             super.toString(builder);
    608             builder.append(',');
    609             builder.append("dataSim=").append(dataSim).append(',');
    610             builder.append("networkName=").append(networkName).append(',');
    611             builder.append("networkNameData=").append(networkNameData).append(',');
    612             builder.append("dataConnected=").append(dataConnected).append(',');
    613             builder.append("roaming=").append(roaming).append(',');
    614             builder.append("isDefault=").append(isDefault).append(',');
    615             builder.append("isEmergency=").append(isEmergency).append(',');
    616             builder.append("airplaneMode=").append(airplaneMode).append(',');
    617             builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode)
    618                     .append(',');
    619             builder.append("userSetup=").append(userSetup);
    620         }
    621 
    622         @Override
    623         public boolean equals(Object o) {
    624             return super.equals(o)
    625                     && Objects.equals(((MobileState) o).networkName, networkName)
    626                     && Objects.equals(((MobileState) o).networkNameData, networkNameData)
    627                     && ((MobileState) o).dataSim == dataSim
    628                     && ((MobileState) o).dataConnected == dataConnected
    629                     && ((MobileState) o).isEmergency == isEmergency
    630                     && ((MobileState) o).airplaneMode == airplaneMode
    631                     && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
    632                     && ((MobileState) o).userSetup == userSetup
    633                     && ((MobileState) o).isDefault == isDefault
    634                     && ((MobileState) o).roaming == roaming;
    635         }
    636     }
    637 }
    638