MobileSignalController.java revision da68f596282e60bee832dff07cc96bf64bd15939
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);
242da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        // Only send data sim callbacks to QS.
243da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mCurrentState.dataSim) {
244da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            int qsTypeIcon = mCurrentState.dataConnected ?
245da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    icons.mQsDataType[mCurrentState.inetForNetwork] : 0;
246da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            int length = mSignalsChangedCallbacks.size();
247da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            for (int i = 0; i < length; i++) {
248da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                mSignalsChangedCallbacks.get(i).onMobileDataSignalChanged(mCurrentState.enabled
249da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        && !mCurrentState.isEmergency && !mCurrentState.airplaneMode,
250da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        getQsCurrentIconId(), contentDescription,
251da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        qsTypeIcon,
252da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        mCurrentState.dataConnected && mCurrentState.activityIn,
253da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        mCurrentState.dataConnected && mCurrentState.activityOut,
254da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        dataContentDescription,
255da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        mCurrentState.isEmergency ? null : mCurrentState.networkName,
256da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        // Only wide if actually showing something.
257da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        icons.mIsWide && qsTypeIcon != 0);
258da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
259da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
260da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        boolean showDataIcon = mCurrentState.dataConnected && mCurrentState.inetForNetwork != 0
261da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                || mCurrentState.iconGroup == TelephonyIcons.ROAMING;
262da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        int typeIcon = showDataIcon ? icons.mDataType : 0;
263da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        int signalClustersLength = mSignalClusters.size();
264da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        for (int i = 0; i < signalClustersLength; i++) {
265da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mSignalClusters.get(i).setMobileDataIndicators(
266da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    mCurrentState.enabled && !mCurrentState.airplaneMode,
267da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    getCurrentIconId(),
268da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    typeIcon,
269da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    contentDescription,
270da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    dataContentDescription,
271da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    // Only wide if actually showing something.
272da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    icons.mIsWide && typeIcon != 0,
273da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    mSubscriptionInfo.getSubscriptionId());
274da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
275da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
276da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
277da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    @Override
278da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    protected MobileState cleanState() {
279da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        return new MobileState();
280da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
281da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
282da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private boolean hasService() {
283da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mServiceState != null) {
284da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // Consider the device to be in service if either voice or data
285da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // service is available. Some SIM cards are marketed as data-only
286da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // and do not support voice service, and on these SIM cards, we
287da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // want to show signal bars for data service as well as the "no
288da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // service" or "emergency calls only" text that indicates that voice
289da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // is not available.
290da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            switch (mServiceState.getVoiceRegState()) {
291da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                case ServiceState.STATE_POWER_OFF:
292da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    return false;
293da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                case ServiceState.STATE_OUT_OF_SERVICE:
294da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                case ServiceState.STATE_EMERGENCY_ONLY:
295da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
296da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                default:
297da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    return true;
298da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
299da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
300da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            return false;
301da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
302da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
303da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
304da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private boolean isCdma() {
305da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        return (mSignalStrength != null) && !mSignalStrength.isGsm();
306da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
307da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
308da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public boolean isEmergencyOnly() {
309da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        return (mServiceState != null && mServiceState.isEmergencyOnly());
310da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
311da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
312da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private boolean isRoaming() {
313da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (isCdma()) {
314da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            final int iconMode = mServiceState.getCdmaEriIconMode();
315da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
316da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
317da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
318da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
319da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            return mServiceState != null && mServiceState.getRoaming();
320da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
321da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
322da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
323da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public void handleBroadcast(Intent intent) {
324da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        String action = intent.getAction();
325da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
326da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
327da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
328da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
329da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
330da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            notifyListenersIfNecessary();
331da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
332da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            updateDataSim();
333da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
334da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
335da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
336da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private void updateDataSim() {
337da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        int defaultDataSub = SubscriptionManager.getDefaultDataSubId();
338da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) {
339da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId();
340da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
341da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // There doesn't seem to be a data sim selected, however if
342da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // there isn't a MobileSignalController with dataSim set, then
343da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // QS won't get any callbacks and will be blank.  Instead
344da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // lets just assume we are the data sim (which will basically
345da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // show one at random) in QS until one is selected.  The user
346da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // should pick one soon after, so we shouldn't be in this state
347da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            // for long.
348da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.dataSim = true;
349da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
350da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        notifyListenersIfNecessary();
351da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
352da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
353da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    /**
354da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * Updates the network's name based on incoming spn and plmn.
355da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     */
356da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
357da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (CHATTY) {
358da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
359da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
360da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
361da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        StringBuilder str = new StringBuilder();
362da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (showPlmn && plmn != null) {
363da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            str.append(plmn);
364da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
365da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (showSpn && spn != null) {
366da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (str.length() != 0) {
367da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                str.append(mNetworkNameSeparator);
368da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
369da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            str.append(spn);
370da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
371da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (str.length() != 0) {
372da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.networkName = str.toString();
373da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
374da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.networkName = mNetworkNameDefault;
375da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
376da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
377da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
378da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    /**
379da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
380da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * mDataState, and mSimState.  It should be called any time one of these is updated.
381da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * This will call listeners if necessary.
382da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     */
383da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private final void updateTelephony() {
384da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (DEBUG) {
385da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService()
386da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    + " ss=" + mSignalStrength);
387da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
388da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.connected = hasService() && mSignalStrength != null;
389da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mCurrentState.connected) {
390da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
391da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                mCurrentState.level = mSignalStrength.getCdmaLevel();
392da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            } else {
393da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                mCurrentState.level = mSignalStrength.getLevel();
394da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
395da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
396da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
397da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
398da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        } else {
399da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.iconGroup = mDefaultIcons;
400da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
401da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.dataConnected = mCurrentState.connected
402da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                && mDataState == TelephonyManager.DATA_CONNECTED;
403da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
404da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (isRoaming()) {
405da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.iconGroup = TelephonyIcons.ROAMING;
406da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
407da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (isEmergencyOnly() != mCurrentState.isEmergency) {
408da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.isEmergency = isEmergencyOnly();
409da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mNetworkController.recalculateEmergency();
410da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
411da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        // Fill in the network name if we think we have it.
412da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null
413da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                && mServiceState.getOperatorAlphaShort() != null) {
414da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
415da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
416da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        notifyListenersIfNecessary();
417da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
418da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
419da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    @VisibleForTesting
420da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    void setActivity(int activity) {
421da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
422da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                || activity == TelephonyManager.DATA_ACTIVITY_IN;
423da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
424da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                || activity == TelephonyManager.DATA_ACTIVITY_OUT;
425da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        notifyListenersIfNecessary();
426da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
427da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
428da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    @Override
429da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public void dump(PrintWriter pw) {
430da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        super.dump(pw);
431da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        pw.println("  mSubscription=" + mSubscriptionInfo + ",");
432da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        pw.println("  mServiceState=" + mServiceState + ",");
433da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        pw.println("  mSignalStrength=" + mSignalStrength + ",");
434da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        pw.println("  mDataState=" + mDataState + ",");
435da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        pw.println("  mDataNetType=" + mDataNetType + ",");
436da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
437da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
438da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    class MobilePhoneStateListener extends PhoneStateListener {
439da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public MobilePhoneStateListener(int subId) {
440da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            super(subId);
441da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
442da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
443da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
444da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
445da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (DEBUG) {
446da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength +
447da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
448da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
449da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mSignalStrength = signalStrength;
450da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            updateTelephony();
451da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
452da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
453da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
454da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void onServiceStateChanged(ServiceState state) {
455da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (DEBUG) {
456da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
457da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        + " dataState=" + state.getDataRegState());
458da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
459da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mServiceState = state;
460da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            updateTelephony();
461da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
462da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
463da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
464da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void onDataConnectionStateChanged(int state, int networkType) {
465da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (DEBUG) {
466da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                Log.d(mTag, "onDataConnectionStateChanged: state=" + state
467da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        + " type=" + networkType);
468da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
469da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mDataState = state;
470da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mDataNetType = networkType;
471da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            updateTelephony();
472da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
473da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
474da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
475da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void onDataActivity(int direction) {
476da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            if (DEBUG) {
477da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                Log.d(mTag, "onDataActivity: direction=" + direction);
478da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
479da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            setActivity(direction);
480da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
481da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    };
482da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
483da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    static class MobileIconGroup extends SignalController.IconGroup {
484da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        final int mDataContentDescription; // mContentDescriptionDataType
485da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        final int mDataType;
486da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        final boolean mIsWide;
487da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        final int[] mQsDataType;
488da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
489da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
490da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
491da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
492da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                int[] qsDataType) {
493da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
494da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    qsDiscState, discContentDesc);
495da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mDataContentDescription = dataContentDesc;
496da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mDataType = dataType;
497da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mIsWide = isWide;
498da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mQsDataType = qsDataType;
499da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
500da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
501da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
502da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    static class MobileState extends SignalController.State {
503da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        String networkName;
504da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        boolean dataSim;
505da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        boolean dataConnected;
506da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        boolean isEmergency;
507da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        boolean airplaneMode;
508da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        int inetForNetwork;
509da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
510da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
511da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void copyFrom(State s) {
512da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            super.copyFrom(s);
513da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            MobileState state = (MobileState) s;
514da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            dataSim = state.dataSim;
515da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            networkName = state.networkName;
516da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            dataConnected = state.dataConnected;
517da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            inetForNetwork = state.inetForNetwork;
518da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            isEmergency = state.isEmergency;
519da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            airplaneMode = state.airplaneMode;
520da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
521da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
522da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
523da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        protected void toString(StringBuilder builder) {
524da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            super.toString(builder);
525da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append(',');
526da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append("dataSim=").append(dataSim).append(',');
527da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append("networkName=").append(networkName).append(',');
528da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append("dataConnected=").append(dataConnected).append(',');
529da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append("inetForNetwork=").append(inetForNetwork).append(',');
530da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append("isEmergency=").append(isEmergency).append(',');
531da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            builder.append("airplaneMode=").append(airplaneMode);
532da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
533da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
534da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
535da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public boolean equals(Object o) {
536da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            return super.equals(o)
537da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && Objects.equals(((MobileState) o).networkName, networkName)
538da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && ((MobileState) o).dataSim == dataSim
539da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && ((MobileState) o).dataConnected == dataConnected
540da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && ((MobileState) o).isEmergency == isEmergency
541da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && ((MobileState) o).airplaneMode == airplaneMode
542da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    && ((MobileState) o).inetForNetwork == inetForNetwork;
543da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
544da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
545da68f596282e60bee832dff07cc96bf64bd15939Jason Monk}
546