1da68f596282e60bee832dff07cc96bf64bd15939Jason Monk/*
2da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * Copyright (C) 2015 The Android Open Source Project
3da68f596282e60bee832dff07cc96bf64bd15939Jason Monk *
4da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * Licensed under the Apache License, Version 2.0 (the "License");
5da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * you may not use this file except in compliance with the License.
6da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * You may obtain a copy of the License at
7da68f596282e60bee832dff07cc96bf64bd15939Jason Monk *
8da68f596282e60bee832dff07cc96bf64bd15939Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
9da68f596282e60bee832dff07cc96bf64bd15939Jason Monk *
10da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * Unless required by applicable law or agreed to in writing, software
11da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * distributed under the License is distributed on an "AS IS" BASIS,
12da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * See the License for the specific language governing permissions and
14da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * limitations under the License.
15da68f596282e60bee832dff07cc96bf64bd15939Jason Monk */
16da68f596282e60bee832dff07cc96bf64bd15939Jason Monkpackage com.android.systemui.statusbar.policy;
17da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
18da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.content.Context;
19da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.content.Intent;
200288de0e5635b714273ff8185b4bdbfb9ece447cJason Monkimport android.database.ContentObserver;
21da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.net.NetworkCapabilities;
220288de0e5635b714273ff8185b4bdbfb9ece447cJason Monkimport android.os.Handler;
2307b75fe65dcb5b8add8246654c65f95f1191933eJason Monkimport android.os.Looper;
240288de0e5635b714273ff8185b4bdbfb9ece447cJason Monkimport android.provider.Settings.Global;
25da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.telephony.PhoneStateListener;
26da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.telephony.ServiceState;
27da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.telephony.SignalStrength;
28da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.telephony.SubscriptionInfo;
29da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.telephony.SubscriptionManager;
30da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.telephony.TelephonyManager;
3193fb68fdce8f0d28eaa77704e4b00933260b83ddJason Monkimport android.text.TextUtils;
32da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.util.Log;
33da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.util.SparseArray;
34da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
35da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport com.android.internal.annotations.VisibleForTesting;
36da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport com.android.internal.telephony.TelephonyIntents;
37da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport com.android.internal.telephony.cdma.EriInfo;
38da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport com.android.systemui.R;
3948edc0c62805450fcecd11622dbcc91a433dcd0cJason Monkimport com.android.systemui.statusbar.phone.SignalDrawable;
4007b75fe65dcb5b8add8246654c65f95f1191933eJason Monkimport com.android.systemui.statusbar.policy.NetworkController.IconState;
41e06b065f6e0d0f939b8519ccd3699b90aef818e9Jason Monkimport com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
42da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
43c6cc6266c9325f180b1a073f733fdf0a64e9286fJason Monkimport com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
44da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
45da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport java.io.PrintWriter;
4633f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monkimport java.util.BitSet;
47da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport java.util.Objects;
48da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
49da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
50da68f596282e60bee832dff07cc96bf64bd15939Jason Monkpublic class MobileSignalController extends SignalController<
51da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> {
52da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private final TelephonyManager mPhone;
53c6cc6266c9325f180b1a073f733fdf0a64e9286fJason Monk    private final SubscriptionDefaults mDefaults;
54da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private final String mNetworkNameDefault;
55da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private final String mNetworkNameSeparator;
560288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk    private final ContentObserver mObserver;
57da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    @VisibleForTesting
58da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    final PhoneStateListener mPhoneStateListener;
59da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    // Save entire info for logging, we only use the id.
6066845a36c9eeca5296a2bf86793a5d6bedac1b36Jason Monk    final SubscriptionInfo mSubscriptionInfo;
61da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
62da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    // @VisibleForDemoMode
63da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    final SparseArray<MobileIconGroup> mNetworkToIconLookup;
64da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
65da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    // Since some pieces of the phone state are interdependent we store it locally,
66da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    // this could potentially become part of MobileState for simplification/complication
67da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    // of code.
68da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
69da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private int mDataState = TelephonyManager.DATA_DISCONNECTED;
70da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private ServiceState mServiceState;
71da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private SignalStrength mSignalStrength;
72da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private MobileIconGroup mDefaultIcons;
73da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private Config mConfig;
74da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
75da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
76da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    // need listener lists anymore.
77da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public MobileSignalController(Context context, Config config, boolean hasMobileData,
7807b75fe65dcb5b8add8246654c65f95f1191933eJason Monk            TelephonyManager phone, CallbackHandler callbackHandler,
79c6cc6266c9325f180b1a073f733fdf0a64e9286fJason Monk            NetworkControllerImpl networkController, SubscriptionInfo info,
80c6cc6266c9325f180b1a073f733fdf0a64e9286fJason Monk            SubscriptionDefaults defaults, Looper receiverLooper) {
81da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
8207b75fe65dcb5b8add8246654c65f95f1191933eJason Monk                NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
83da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                networkController);
84da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup = new SparseArray<>();
85da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mConfig = config;
86da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mPhone = phone;
87c6cc6266c9325f180b1a073f733fdf0a64e9286fJason Monk        mDefaults = defaults;
88da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mSubscriptionInfo = info;
8907b75fe65dcb5b8add8246654c65f95f1191933eJason Monk        mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(),
9007b75fe65dcb5b8add8246654c65f95f1191933eJason Monk                receiverLooper);
91da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
92da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkNameDefault = getStringIfExists(
93da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                com.android.internal.R.string.lockscreen_carrier_default);
94da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
95da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mapIconSets();
96da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
9700aa9d4427cd6ca00edcbc1b7915bc22ac580d6aJason Monk        String networkName = info.getCarrierName() != null ? info.getCarrierName().toString()
9800aa9d4427cd6ca00edcbc1b7915bc22ac580d6aJason Monk                : mNetworkNameDefault;
9900aa9d4427cd6ca00edcbc1b7915bc22ac580d6aJason Monk        mLastState.networkName = mCurrentState.networkName = networkName;
10000aa9d4427cd6ca00edcbc1b7915bc22ac580d6aJason Monk        mLastState.networkNameData = mCurrentState.networkNameData = networkName;
101da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mLastState.enabled = mCurrentState.enabled = hasMobileData;
102da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
103da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        // Get initial data sim state.
104da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        updateDataSim();
1050288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk        mObserver = new ContentObserver(new Handler(receiverLooper)) {
1060288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk            @Override
1070288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk            public void onChange(boolean selfChange) {
1080288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk                updateTelephony();
1090288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk            }
1100288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk        };
111da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
112da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
113da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public void setConfiguration(Config config) {
114da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mConfig = config;
115da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mapIconSets();
116da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        updateTelephony();
117da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
118da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
119da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public int getDataContentDescription() {
120da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        return getIcons().mDataContentDescription;
121da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
122da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
123da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public void setAirplaneMode(boolean airplaneMode) {
124da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.airplaneMode = airplaneMode;
125da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        notifyListenersIfNecessary();
126da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
127da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
128fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk    public void setUserSetupComplete(boolean userSetup) {
129fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk        mCurrentState.userSetup = userSetup;
130fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk        notifyListenersIfNecessary();
131fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk    }
132fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk
13333f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk    @Override
13433f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk    public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
13533f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk        boolean isValidated = validatedTransports.get(mTransportType);
13633f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk        mCurrentState.isDefault = connectedTransports.get(mTransportType);
13733f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk        // Only show this as not having connectivity if we are default.
13833f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk        mCurrentState.inetCondition = (isValidated || !mCurrentState.isDefault) ? 1 : 0;
13933f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk        notifyListenersIfNecessary();
140da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
141da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
142a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn    public void setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode) {
143a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn        mCurrentState.carrierNetworkChangeMode = carrierNetworkChangeMode;
1442fdbe128209f02725c645f29bff941efe865da56Andrew Flynn        updateTelephony();
145a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn    }
146a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn
147da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    /**
148da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * Start listening for phone state changes.
149da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     */
150da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public void registerListener() {
151da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mPhone.listen(mPhoneStateListener,
152da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                PhoneStateListener.LISTEN_SERVICE_STATE
153da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
154da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        | PhoneStateListener.LISTEN_CALL_STATE
155da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
156a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn                        | PhoneStateListener.LISTEN_DATA_ACTIVITY
157a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn                        | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
1580288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk        mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA),
1590288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk                true, mObserver);
1600288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk        mContext.getContentResolver().registerContentObserver(Global.getUriFor(
1610288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk                Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()),
1620288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk                true, mObserver);
163da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
164da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
165da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    /**
166da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * Stop listening for phone state changes.
167da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     */
168da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public void unregisterListener() {
169da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mPhone.listen(mPhoneStateListener, 0);
1700288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk        mContext.getContentResolver().unregisterContentObserver(mObserver);
171da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
172da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
173da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    /**
174da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * Produce a mapping of data network types to icon groups for simple and quick use in
175da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * updateTelephony.
176da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     */
177da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private void mapIconSets() {
178da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup.clear();
179da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
180da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G);
181da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G);
182da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G);
183da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
184da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
185da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
186da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (!mConfig.showAtLeast3G) {
187da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
188da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    TelephonyIcons.UNKNOWN);
189da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E);
190da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X);
191da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X);
192da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
193da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mDefaultIcons = TelephonyIcons.G;
194da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
195da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
196da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    TelephonyIcons.THREE_G);
197da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE,
198da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    TelephonyIcons.THREE_G);
199da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA,
200da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    TelephonyIcons.THREE_G);
201da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT,
202da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    TelephonyIcons.THREE_G);
203da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mDefaultIcons = TelephonyIcons.THREE_G;
204da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
205da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
206da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        MobileIconGroup hGroup = TelephonyIcons.THREE_G;
207da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mConfig.hspaDataDistinguishable) {
208da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            hGroup = TelephonyIcons.H;
209da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
210da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
211da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
212da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
213da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup);
214da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
215da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mConfig.show4gForLte) {
216da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
21737d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt            if (mConfig.hideLtePlus) {
21837d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
21937d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt                        TelephonyIcons.FOUR_G);
22037d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt            } else {
22137d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
22237d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt                        TelephonyIcons.FOUR_G_PLUS);
22337d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt            }
224da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
225da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
22637d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt            if (mConfig.hideLtePlus) {
22737d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
22837d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt                        TelephonyIcons.LTE);
22937d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt            } else {
23037d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
23137d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt                        TelephonyIcons.LTE_PLUS);
23237d34ba893001d59d0c0a70beea87e00b25e22dfRobert Greenwalt            }
233da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
2347150d7fa357e00b2904ff3bcf9e06a1014bfbb39Jason Monk        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
235da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
236da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
23748edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk    private int getNumLevels() {
23848edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk        return SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
23948edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk    }
24048edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk
24148edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk    @Override
24248edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk    public int getCurrentIconId() {
24348edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk        if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) {
24448edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk            return SignalDrawable.getCarrierChangeState(getNumLevels());
24548edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk        } else if (mCurrentState.connected) {
24648edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk            return SignalDrawable.getState(mCurrentState.level, getNumLevels(),
2477e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk                    mCurrentState.inetCondition == 0);
24848edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk        } else if (mCurrentState.enabled) {
24948edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk            return SignalDrawable.getEmptyState(getNumLevels());
25048edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk        } else {
25148edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk            return 0;
25248edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk        }
25348edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk    }
25448edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk
25548edc0c62805450fcecd11622dbcc91a433dcd0cJason Monk    @Override
25601df36f37fc470d3fd8c120b09cc4e7943cfacfbJason Monk    public int getQsCurrentIconId() {
2573d1aad64754828b0b5f98f2499f125fd4c2b9fbcEvan Laird        if (mCurrentState.airplaneMode) {
2583d1aad64754828b0b5f98f2499f125fd4c2b9fbcEvan Laird            return SignalDrawable.getAirplaneModeState(getNumLevels());
2593d1aad64754828b0b5f98f2499f125fd4c2b9fbcEvan Laird        }
2603d1aad64754828b0b5f98f2499f125fd4c2b9fbcEvan Laird
26101df36f37fc470d3fd8c120b09cc4e7943cfacfbJason Monk        return getCurrentIconId();
26201df36f37fc470d3fd8c120b09cc4e7943cfacfbJason Monk    }
26301df36f37fc470d3fd8c120b09cc4e7943cfacfbJason Monk
26401df36f37fc470d3fd8c120b09cc4e7943cfacfbJason Monk    @Override
265e06b065f6e0d0f939b8519ccd3699b90aef818e9Jason Monk    public void notifyListeners(SignalCallback callback) {
266da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        MobileIconGroup icons = getIcons();
267da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
268da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        String contentDescription = getStringIfExists(getContentDescription());
269da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
2707e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
271fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk                && mCurrentState.userSetup;
2725c7daaf7763f4c1fc3eb44430d1b2e5bf11130e1Jeff Davidson
2730f0de13c37082f9443e3f0c8cc413188ec66d3feJason Monk        // Show icon in QS when we are connected or data is disabled.
2747e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
27507b75fe65dcb5b8add8246654c65f95f1191933eJason Monk        IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
27607b75fe65dcb5b8add8246654c65f95f1191933eJason Monk                getCurrentIconId(), contentDescription);
27707b75fe65dcb5b8add8246654c65f95f1191933eJason Monk
2787e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        int qsTypeIcon = 0;
2797e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        IconState qsIcon = null;
2807e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        String description = null;
2817e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        // Only send data sim callbacks to QS.
2827e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        if (mCurrentState.dataSim) {
28301df36f37fc470d3fd8c120b09cc4e7943cfacfbJason Monk            qsTypeIcon = showDataIcon ? icons.mQsDataType : 0;
2847e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk            qsIcon = new IconState(mCurrentState.enabled
28501df36f37fc470d3fd8c120b09cc4e7943cfacfbJason Monk                    && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
2867e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk            description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
2877e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        }
28807b75fe65dcb5b8add8246654c65f95f1191933eJason Monk        boolean activityIn = mCurrentState.dataConnected
2890288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk                && !mCurrentState.carrierNetworkChangeMode
2900288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk                && mCurrentState.activityIn;
29107b75fe65dcb5b8add8246654c65f95f1191933eJason Monk        boolean activityOut = mCurrentState.dataConnected
2920288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk                && !mCurrentState.carrierNetworkChangeMode
2930288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk                && mCurrentState.activityOut;
2940f0de13c37082f9443e3f0c8cc413188ec66d3feJason Monk        showDataIcon &= mCurrentState.isDefault || dataDisabled;
295da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        int typeIcon = showDataIcon ? icons.mDataType : 0;
2967e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
2977e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk                activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
2987e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk                mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);
299a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn    }
300a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn
301da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    @Override
302da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    protected MobileState cleanState() {
303da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        return new MobileState();
304da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
305da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
306da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private boolean hasService() {
307da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mServiceState != null) {
308da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // Consider the device to be in service if either voice or data
309da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // service is available. Some SIM cards are marketed as data-only
310da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // and do not support voice service, and on these SIM cards, we
311da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // want to show signal bars for data service as well as the "no
312da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // service" or "emergency calls only" text that indicates that voice
313da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // is not available.
314da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            switch (mServiceState.getVoiceRegState()) {
315da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                case ServiceState.STATE_POWER_OFF:
316da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    return false;
317da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                case ServiceState.STATE_OUT_OF_SERVICE:
318da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                case ServiceState.STATE_EMERGENCY_ONLY:
319da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
320da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                default:
321da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    return true;
322da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
323da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
324da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            return false;
325da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
326da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
327da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
328da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private boolean isCdma() {
329da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        return (mSignalStrength != null) && !mSignalStrength.isGsm();
330da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
331da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
332da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public boolean isEmergencyOnly() {
333da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        return (mServiceState != null && mServiceState.isEmergencyOnly());
334da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
335da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
336da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private boolean isRoaming() {
3375e592b4a365feba1b196ae11ce2a581c6da66a29Shishir Agrawal        // During a carrier change, roaming indications need to be supressed.
3385e592b4a365feba1b196ae11ce2a581c6da66a29Shishir Agrawal        if (isCarrierNetworkChangeActive()) {
3395e592b4a365feba1b196ae11ce2a581c6da66a29Shishir Agrawal            return false;
3405e592b4a365feba1b196ae11ce2a581c6da66a29Shishir Agrawal        }
341da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (isCdma()) {
342da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            final int iconMode = mServiceState.getCdmaEriIconMode();
343da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
344da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
3450288de0e5635b714273ff8185b4bdbfb9ece447cJason Monk                    || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
346da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
347da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            return mServiceState != null && mServiceState.getRoaming();
348da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
349da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
350da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
351a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn    private boolean isCarrierNetworkChangeActive() {
35255fc8004ad1896da615fd08caca87d1b393d085cAndrew Flynn        return mCurrentState.carrierNetworkChangeMode;
353a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn    }
354a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn
355da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public void handleBroadcast(Intent intent) {
356da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        String action = intent.getAction();
357da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
358da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
359da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
3605504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak                    intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN),
361da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
362da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
363da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            notifyListenersIfNecessary();
364da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
365da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            updateDataSim();
3668fcab35828144e27a32a95ed9bd83e4f6d83ac21Jason Monk            notifyListenersIfNecessary();
367da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
368da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
369da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
370da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private void updateDataSim() {
371c6cc6266c9325f180b1a073f733fdf0a64e9286fJason Monk        int defaultDataSub = mDefaults.getDefaultDataSubId();
372da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) {
373da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId();
374da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
375da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // There doesn't seem to be a data sim selected, however if
376da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // there isn't a MobileSignalController with dataSim set, then
377da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // QS won't get any callbacks and will be blank.  Instead
378da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // lets just assume we are the data sim (which will basically
379da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // show one at random) in QS until one is selected.  The user
380da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // should pick one soon after, so we shouldn't be in this state
381da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // for long.
382da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.dataSim = true;
383da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
384da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
385da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
386da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    /**
387da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * Updates the network's name based on incoming spn and plmn.
388da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     */
3895504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak    void updateNetworkName(boolean showSpn, String spn, String dataSpn,
3905504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak            boolean showPlmn, String plmn) {
391da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (CHATTY) {
3925504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn
3935504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak                    + " spn=" + spn + " dataSpn=" + dataSpn
394da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
395da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
396da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        StringBuilder str = new StringBuilder();
3975504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak        StringBuilder strData = new StringBuilder();
398da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (showPlmn && plmn != null) {
399da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            str.append(plmn);
4005504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak            strData.append(plmn);
401da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
402da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (showSpn && spn != null) {
403da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (str.length() != 0) {
404da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                str.append(mNetworkNameSeparator);
405da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
406da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            str.append(spn);
407da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
408da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (str.length() != 0) {
409da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.networkName = str.toString();
410da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
411da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.networkName = mNetworkNameDefault;
412da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
4135504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak        if (showSpn && dataSpn != null) {
4145504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak            if (strData.length() != 0) {
4155504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak                strData.append(mNetworkNameSeparator);
4165504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak            }
4175504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak            strData.append(dataSpn);
4185504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak        }
4195504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak        if (strData.length() != 0) {
4205504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak            mCurrentState.networkNameData = strData.toString();
4215504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak        } else {
4225504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak            mCurrentState.networkNameData = mNetworkNameDefault;
4235504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak        }
424da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
425da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
426da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    /**
427da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
428da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * mDataState, and mSimState.  It should be called any time one of these is updated.
429da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * This will call listeners if necessary.
430da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     */
431da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private final void updateTelephony() {
432da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (DEBUG) {
433da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService()
434da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    + " ss=" + mSignalStrength);
435da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
436da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.connected = hasService() && mSignalStrength != null;
437da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mCurrentState.connected) {
438da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
439da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                mCurrentState.level = mSignalStrength.getCdmaLevel();
440da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            } else {
441da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                mCurrentState.level = mSignalStrength.getLevel();
442da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
443da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
444da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
445da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
446da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
447da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.iconGroup = mDefaultIcons;
448da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
449da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.dataConnected = mCurrentState.connected
4507e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk                && mDataState == TelephonyManager.DATA_CONNECTED;
451da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
4520f0de13c37082f9443e3f0c8cc413188ec66d3feJason Monk        mCurrentState.roaming = isRoaming();
453a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn        if (isCarrierNetworkChangeActive()) {
454a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn            mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
4557e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        } else if (isDataDisabled()) {
4567e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk            mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
457da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
458da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (isEmergencyOnly() != mCurrentState.isEmergency) {
459da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.isEmergency = isEmergencyOnly();
460da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkController.recalculateEmergency();
461da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
462da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        // Fill in the network name if we think we have it.
463da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null
46493fb68fdce8f0d28eaa77704e4b00933260b83ddJason Monk                && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
465da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
466da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
467a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn
468da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        notifyListenersIfNecessary();
469da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
470da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
4711a95c86281bc9c2c187b3f4df19d2805595b6f26Jason Monk    private boolean isDataDisabled() {
4721a95c86281bc9c2c187b3f4df19d2805595b6f26Jason Monk        return !mPhone.getDataEnabled(mSubscriptionInfo.getSubscriptionId());
4731a95c86281bc9c2c187b3f4df19d2805595b6f26Jason Monk    }
4741a95c86281bc9c2c187b3f4df19d2805595b6f26Jason Monk
475da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    @VisibleForTesting
476da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    void setActivity(int activity) {
477da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
478da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                || activity == TelephonyManager.DATA_ACTIVITY_IN;
479da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
480da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                || activity == TelephonyManager.DATA_ACTIVITY_OUT;
481da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        notifyListenersIfNecessary();
482da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
483da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
484da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    @Override
485da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public void dump(PrintWriter pw) {
486da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        super.dump(pw);
487da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        pw.println("  mSubscription=" + mSubscriptionInfo + ",");
488da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        pw.println("  mServiceState=" + mServiceState + ",");
489da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        pw.println("  mSignalStrength=" + mSignalStrength + ",");
490da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        pw.println("  mDataState=" + mDataState + ",");
491da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        pw.println("  mDataNetType=" + mDataNetType + ",");
492da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
493da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
494da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    class MobilePhoneStateListener extends PhoneStateListener {
49507b75fe65dcb5b8add8246654c65f95f1191933eJason Monk        public MobilePhoneStateListener(int subId, Looper looper) {
49607b75fe65dcb5b8add8246654c65f95f1191933eJason Monk            super(subId, looper);
497da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
498da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
499da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
500da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
501da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (DEBUG) {
502da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength +
503da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
504da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
505da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mSignalStrength = signalStrength;
506da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            updateTelephony();
507da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
508da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
509da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
510da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void onServiceStateChanged(ServiceState state) {
511da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (DEBUG) {
512da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
513da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        + " dataState=" + state.getDataRegState());
514da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
515da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mServiceState = state;
51667b2c16a9a9060d37888bdab4dfadd384a76e9d7Jason Monk            mDataNetType = state.getDataNetworkType();
517ea0d71390ab528ffea7161674333b0bbab8356dfRobert Greenwalt            if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
518ea0d71390ab528ffea7161674333b0bbab8356dfRobert Greenwalt                    mServiceState.isUsingCarrierAggregation()) {
519ea0d71390ab528ffea7161674333b0bbab8356dfRobert Greenwalt                mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
520ea0d71390ab528ffea7161674333b0bbab8356dfRobert Greenwalt            }
521da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            updateTelephony();
522da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
523da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
524da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
525da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void onDataConnectionStateChanged(int state, int networkType) {
526da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (DEBUG) {
527da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                Log.d(mTag, "onDataConnectionStateChanged: state=" + state
528da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        + " type=" + networkType);
529da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
530da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mDataState = state;
531da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mDataNetType = networkType;
532ea0d71390ab528ffea7161674333b0bbab8356dfRobert Greenwalt            if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
533ea0d71390ab528ffea7161674333b0bbab8356dfRobert Greenwalt                    mServiceState.isUsingCarrierAggregation()) {
534ea0d71390ab528ffea7161674333b0bbab8356dfRobert Greenwalt                mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
535ea0d71390ab528ffea7161674333b0bbab8356dfRobert Greenwalt            }
536da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            updateTelephony();
537da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
538da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
539da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
540da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void onDataActivity(int direction) {
541da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (DEBUG) {
542da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                Log.d(mTag, "onDataActivity: direction=" + direction);
543da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
544da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            setActivity(direction);
545da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
546a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn
547a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn        @Override
548a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn        public void onCarrierNetworkChange(boolean active) {
549a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn            if (DEBUG) {
550a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn                Log.d(mTag, "onCarrierNetworkChange: active=" + active);
551a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn            }
552a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn            mCurrentState.carrierNetworkChangeMode = active;
553a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn
554a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn            updateTelephony();
555a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn        }
556da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    };
557da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
558da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    static class MobileIconGroup extends SignalController.IconGroup {
559da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        final int mDataContentDescription; // mContentDescriptionDataType
560da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        final int mDataType;
561da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        final boolean mIsWide;
56233f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk        final int mQsDataType;
563da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
564da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
565da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
566da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
56733f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk                int qsDataType) {
5682fdbe128209f02725c645f29bff941efe865da56Andrew Flynn            super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
5692fdbe128209f02725c645f29bff941efe865da56Andrew Flynn                    qsDiscState, discContentDesc);
570da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mDataContentDescription = dataContentDesc;
571da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mDataType = dataType;
572da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mIsWide = isWide;
573da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mQsDataType = qsDataType;
574da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
575da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
576da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
577da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    static class MobileState extends SignalController.State {
578da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        String networkName;
5795504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak        String networkNameData;
580da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        boolean dataSim;
581da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        boolean dataConnected;
582da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        boolean isEmergency;
583da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        boolean airplaneMode;
584a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn        boolean carrierNetworkChangeMode;
58533f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk        boolean isDefault;
586fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk        boolean userSetup;
5870f0de13c37082f9443e3f0c8cc413188ec66d3feJason Monk        boolean roaming;
588da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
589da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
590da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void copyFrom(State s) {
591da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            super.copyFrom(s);
592da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            MobileState state = (MobileState) s;
593da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            dataSim = state.dataSim;
594da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            networkName = state.networkName;
5955504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak            networkNameData = state.networkNameData;
596da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            dataConnected = state.dataConnected;
59733f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk            isDefault = state.isDefault;
598da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            isEmergency = state.isEmergency;
599da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            airplaneMode = state.airplaneMode;
600a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn            carrierNetworkChangeMode = state.carrierNetworkChangeMode;
601fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk            userSetup = state.userSetup;
6020f0de13c37082f9443e3f0c8cc413188ec66d3feJason Monk            roaming = state.roaming;
603da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
604da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
605da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
606da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        protected void toString(StringBuilder builder) {
607da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            super.toString(builder);
608da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append(',');
609da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append("dataSim=").append(dataSim).append(',');
610da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append("networkName=").append(networkName).append(',');
6115504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak            builder.append("networkNameData=").append(networkNameData).append(',');
612da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append("dataConnected=").append(dataConnected).append(',');
6130f0de13c37082f9443e3f0c8cc413188ec66d3feJason Monk            builder.append("roaming=").append(roaming).append(',');
61433f8ae7543fbf7d94266f0f1621ec873aa2542f1Jason Monk            builder.append("isDefault=").append(isDefault).append(',');
615da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append("isEmergency=").append(isEmergency).append(',');
616a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn            builder.append("airplaneMode=").append(airplaneMode).append(',');
617fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk            builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode)
618fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk                    .append(',');
619fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk            builder.append("userSetup=").append(userSetup);
620da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
621da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
622da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
623da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public boolean equals(Object o) {
624da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            return super.equals(o)
625da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && Objects.equals(((MobileState) o).networkName, networkName)
6265504d39b7f880fa8b8660e5d4b014ec559124cf9Pavel Zhamaitsiak                    && Objects.equals(((MobileState) o).networkNameData, networkNameData)
627da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && ((MobileState) o).dataSim == dataSim
628da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && ((MobileState) o).dataConnected == dataConnected
629da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && ((MobileState) o).isEmergency == isEmergency
630da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && ((MobileState) o).airplaneMode == airplaneMode
631a478d70a68696380acbd4a9739dfaaebff61c728Andrew Flynn                    && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
632fd57ea730e65afd6dcb848664dde0cdb64624659Jason Monk                    && ((MobileState) o).userSetup == userSetup
6330f0de13c37082f9443e3f0c8cc413188ec66d3feJason Monk                    && ((MobileState) o).isDefault == isDefault
6340f0de13c37082f9443e3f0c8cc413188ec66d3feJason Monk                    && ((MobileState) o).roaming == roaming;
635da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
636da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
637da68f596282e60bee832dff07cc96bf64bd15939Jason Monk}
638