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