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