NetworkController.java revision 3c87566c115e1fce3fdc09a6fe40488bcdc04cde
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar.policy;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.content.res.Resources;
24import android.net.ConnectivityManager;
25import android.net.NetworkInfo;
26import android.net.wifi.WifiConfiguration;
27import android.net.wifi.WifiInfo;
28import android.net.wifi.WifiManager;
29import android.net.wimax.WimaxManagerConstants;
30import android.os.Bundle;
31import android.os.Handler;
32import android.os.Message;
33import android.os.Messenger;
34import android.provider.Settings;
35import android.telephony.PhoneStateListener;
36import android.telephony.ServiceState;
37import android.telephony.SignalStrength;
38import android.telephony.TelephonyManager;
39import android.util.Log;
40import android.view.View;
41import android.widget.TextView;
42
43import com.android.internal.telephony.IccCardConstants;
44import com.android.internal.telephony.TelephonyIntents;
45import com.android.internal.telephony.cdma.EriInfo;
46import com.android.internal.util.AsyncChannel;
47import com.android.systemui.DemoMode;
48import com.android.systemui.R;
49
50import java.io.FileDescriptor;
51import java.io.PrintWriter;
52import java.util.ArrayList;
53import java.util.List;
54import java.util.Locale;
55
56public class NetworkController extends BroadcastReceiver implements DemoMode {
57    // debug
58    static final String TAG = "StatusBar.NetworkController";
59    static final boolean DEBUG = false;
60    static final boolean CHATTY = false; // additional diagnostics, but not logspew
61
62    private static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_signal_flightmode;
63
64    // telephony
65    boolean mHspaDataDistinguishable;
66    final TelephonyManager mPhone;
67    boolean mDataConnected;
68    IccCardConstants.State mSimState = IccCardConstants.State.READY;
69    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
70    int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
71    int mDataState = TelephonyManager.DATA_DISCONNECTED;
72    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
73    ServiceState mServiceState;
74    SignalStrength mSignalStrength;
75    int[] mDataIconList = TelephonyIcons.DATA_G[0];
76    String mNetworkName;
77    String mNetworkNameDefault;
78    String mNetworkNameSeparator;
79    int mPhoneSignalIconId;
80    int mQSPhoneSignalIconId;
81    int mDataDirectionIconId; // data + data direction on phones
82    int mDataSignalIconId;
83    int mDataTypeIconId;
84    int mQSDataTypeIconId;
85    int mAirplaneIconId;
86    boolean mDataActive;
87    int mLastSignalLevel;
88    boolean mShowPhoneRSSIForData = false;
89    boolean mShowAtLeastThreeGees = false;
90    boolean mAlwaysShowCdmaRssi = false;
91
92    String mContentDescriptionPhoneSignal;
93    String mContentDescriptionWifi;
94    String mContentDescriptionWimax;
95    String mContentDescriptionCombinedSignal;
96    String mContentDescriptionDataType;
97
98    // wifi
99    final WifiManager mWifiManager;
100    AsyncChannel mWifiChannel;
101    boolean mWifiEnabled, mWifiConnected;
102    int mWifiRssi, mWifiLevel;
103    String mWifiSsid;
104    int mWifiIconId = 0;
105    int mQSWifiIconId = 0;
106    int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
107
108    // bluetooth
109    private boolean mBluetoothTethered = false;
110    private int mBluetoothTetherIconId =
111        com.android.internal.R.drawable.stat_sys_tether_bluetooth;
112
113    //wimax
114    private boolean mWimaxSupported = false;
115    private boolean mIsWimaxEnabled = false;
116    private boolean mWimaxConnected = false;
117    private boolean mWimaxIdle = false;
118    private int mWimaxIconId = 0;
119    private int mWimaxSignal = 0;
120    private int mWimaxState = 0;
121    private int mWimaxExtraState = 0;
122
123    // data connectivity (regardless of state, can we access the internet?)
124    // state of inet connection - 0 not connected, 100 connected
125    private boolean mConnected = false;
126    private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
127    private String mConnectedNetworkTypeName;
128    private int mInetCondition = 0;
129    private static final int INET_CONDITION_THRESHOLD = 50;
130
131    private boolean mAirplaneMode = false;
132    private boolean mLastAirplaneMode = true;
133
134    private Locale mLocale = null;
135    private Locale mLastLocale = null;
136
137    // our ui
138    Context mContext;
139    ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
140    ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
141    ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
142    ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
143    ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
144    ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
145            new ArrayList<NetworkSignalChangedCallback>();
146    int mLastPhoneSignalIconId = -1;
147    int mLastDataDirectionIconId = -1;
148    int mLastWifiIconId = -1;
149    int mLastWimaxIconId = -1;
150    int mLastCombinedSignalIconId = -1;
151    int mLastDataTypeIconId = -1;
152    String mLastCombinedLabel = "";
153
154    private boolean mHasMobileDataFeature;
155
156    boolean mDataAndWifiStacked = false;
157
158    public interface SignalCluster {
159        void setWifiIndicators(boolean visible, int strengthIcon,
160                String contentDescription);
161        void setMobileDataIndicators(boolean visible, int strengthIcon,
162                int typeIcon, String contentDescription, String typeContentDescription);
163        void setIsAirplaneMode(boolean is, int airplaneIcon);
164    }
165
166    public interface NetworkSignalChangedCallback {
167        void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
168                String wifitSignalContentDescriptionId, String description);
169        void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
170                String mobileSignalContentDescriptionId, int dataTypeIconId,
171                String dataTypeContentDescriptionId, String description);
172        void onAirplaneModeChanged(boolean enabled);
173    }
174
175    /**
176     * Construct this controller object and register for updates.
177     */
178    public NetworkController(Context context) {
179        mContext = context;
180        final Resources res = context.getResources();
181
182        ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
183                Context.CONNECTIVITY_SERVICE);
184        mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
185
186        mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
187        mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
188        mAlwaysShowCdmaRssi = res.getBoolean(
189                com.android.internal.R.bool.config_alwaysUseCdmaRssi);
190
191        // set up the default wifi icon, used when no radios have ever appeared
192        updateWifiIcons();
193        updateWimaxIcons();
194
195        // telephony
196        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
197        mPhone.listen(mPhoneStateListener,
198                          PhoneStateListener.LISTEN_SERVICE_STATE
199                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
200                        | PhoneStateListener.LISTEN_CALL_STATE
201                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
202                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
203        mHspaDataDistinguishable = mContext.getResources().getBoolean(
204                R.bool.config_hspa_data_distinguishable);
205        mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
206        mNetworkNameDefault = mContext.getString(
207                com.android.internal.R.string.lockscreen_carrier_default);
208        mNetworkName = mNetworkNameDefault;
209
210        // wifi
211        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
212        Handler handler = new WifiHandler();
213        mWifiChannel = new AsyncChannel();
214        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
215        if (wifiMessenger != null) {
216            mWifiChannel.connect(mContext, handler, wifiMessenger);
217        }
218
219        // broadcasts
220        IntentFilter filter = new IntentFilter();
221        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
222        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
223        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
224        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
225        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
226        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
227        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
228        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
229        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
230        mWimaxSupported = mContext.getResources().getBoolean(
231                com.android.internal.R.bool.config_wimaxEnabled);
232        if(mWimaxSupported) {
233            filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
234            filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
235            filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
236        }
237        context.registerReceiver(this, filter);
238
239        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
240        updateAirplaneMode();
241
242        mLastLocale = mContext.getResources().getConfiguration().locale;
243    }
244
245    public boolean hasMobileDataFeature() {
246        return mHasMobileDataFeature;
247    }
248
249    public boolean hasVoiceCallingFeature() {
250        return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
251    }
252
253    public boolean isEmergencyOnly() {
254        return (mServiceState != null && mServiceState.isEmergencyOnly());
255    }
256
257    public void addCombinedLabelView(TextView v) {
258        mCombinedLabelViews.add(v);
259    }
260
261    public void addMobileLabelView(TextView v) {
262        mMobileLabelViews.add(v);
263    }
264
265    public void addWifiLabelView(TextView v) {
266        mWifiLabelViews.add(v);
267    }
268
269    public void addEmergencyLabelView(TextView v) {
270        mEmergencyLabelViews.add(v);
271    }
272
273    public void addSignalCluster(SignalCluster cluster) {
274        mSignalClusters.add(cluster);
275        refreshSignalCluster(cluster);
276    }
277
278    public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
279        mSignalsChangedCallbacks.add(cb);
280        notifySignalsChangedCallbacks(cb);
281    }
282
283    public void refreshSignalCluster(SignalCluster cluster) {
284        if (mDemoMode) return;
285        cluster.setWifiIndicators(
286                // only show wifi in the cluster if connected or if wifi-only
287                mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
288                mWifiIconId,
289                mContentDescriptionWifi);
290
291        if (mIsWimaxEnabled && mWimaxConnected) {
292            // wimax is special
293            cluster.setMobileDataIndicators(
294                    true,
295                    mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
296                    mDataTypeIconId,
297                    mContentDescriptionWimax,
298                    mContentDescriptionDataType);
299        } else {
300            // normal mobile data
301            cluster.setMobileDataIndicators(
302                    mHasMobileDataFeature,
303                    mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
304                    mDataTypeIconId,
305                    mContentDescriptionPhoneSignal,
306                    mContentDescriptionDataType);
307        }
308        cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
309    }
310
311    void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
312        // only show wifi in the cluster if connected or if wifi-only
313        boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
314        String wifiDesc = wifiEnabled ?
315                mWifiSsid : null;
316        cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, mContentDescriptionWifi, wifiDesc);
317
318        if (isEmergencyOnly()) {
319            cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
320                    mContentDescriptionPhoneSignal, mQSDataTypeIconId, mContentDescriptionDataType,
321                    null);
322        } else {
323            if (mIsWimaxEnabled && mWimaxConnected) {
324                // Wimax is special
325                cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
326                        mContentDescriptionPhoneSignal, mQSDataTypeIconId,
327                        mContentDescriptionDataType, mNetworkName);
328            } else {
329                // Normal mobile data
330                cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
331                        mContentDescriptionPhoneSignal, mQSDataTypeIconId,
332                        mContentDescriptionDataType, mNetworkName);
333            }
334        }
335        cb.onAirplaneModeChanged(mAirplaneMode);
336    }
337
338    public void setStackedMode(boolean stacked) {
339        mDataAndWifiStacked = true;
340    }
341
342    @Override
343    public void onReceive(Context context, Intent intent) {
344        final String action = intent.getAction();
345        if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
346                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
347                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
348            updateWifiState(intent);
349            refreshViews();
350        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
351            updateSimState(intent);
352            updateDataIcon();
353            refreshViews();
354        } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
355            updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
356                        intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
357                        intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
358                        intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
359            refreshViews();
360        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
361                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
362            updateConnectivity(intent);
363            refreshViews();
364        } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
365            refreshLocale();
366            refreshViews();
367        } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
368            refreshLocale();
369            updateAirplaneMode();
370            refreshViews();
371        } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
372                action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
373                action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
374            updateWimaxState(intent);
375            refreshViews();
376        }
377    }
378
379
380    // ===== Telephony ==============================================================
381
382    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
383        @Override
384        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
385            if (DEBUG) {
386                Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
387                    ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
388            }
389            mSignalStrength = signalStrength;
390            updateTelephonySignalStrength();
391            refreshViews();
392        }
393
394        @Override
395        public void onServiceStateChanged(ServiceState state) {
396            if (DEBUG) {
397                Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
398                        + " dataState=" + state.getDataRegState());
399            }
400            mServiceState = state;
401            updateTelephonySignalStrength();
402            updateDataNetType();
403            updateDataIcon();
404            refreshViews();
405        }
406
407        @Override
408        public void onCallStateChanged(int state, String incomingNumber) {
409            if (DEBUG) {
410                Log.d(TAG, "onCallStateChanged state=" + state);
411            }
412            // In cdma, if a voice call is made, RSSI should switch to 1x.
413            if (isCdma()) {
414                updateTelephonySignalStrength();
415                refreshViews();
416            }
417        }
418
419        @Override
420        public void onDataConnectionStateChanged(int state, int networkType) {
421            if (DEBUG) {
422                Log.d(TAG, "onDataConnectionStateChanged: state=" + state
423                        + " type=" + networkType);
424            }
425            mDataState = state;
426            mDataNetType = networkType;
427            updateDataNetType();
428            updateDataIcon();
429            refreshViews();
430        }
431
432        @Override
433        public void onDataActivity(int direction) {
434            if (DEBUG) {
435                Log.d(TAG, "onDataActivity: direction=" + direction);
436            }
437            mDataActivity = direction;
438            updateDataIcon();
439            refreshViews();
440        }
441    };
442
443    private final void updateSimState(Intent intent) {
444        String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
445        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
446            mSimState = IccCardConstants.State.ABSENT;
447        }
448        else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
449            mSimState = IccCardConstants.State.READY;
450        }
451        else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
452            final String lockedReason =
453                    intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
454            if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
455                mSimState = IccCardConstants.State.PIN_REQUIRED;
456            }
457            else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
458                mSimState = IccCardConstants.State.PUK_REQUIRED;
459            }
460            else {
461                mSimState = IccCardConstants.State.NETWORK_LOCKED;
462            }
463        } else {
464            mSimState = IccCardConstants.State.UNKNOWN;
465        }
466    }
467
468    private boolean isCdma() {
469        return (mSignalStrength != null) && !mSignalStrength.isGsm();
470    }
471
472    private boolean hasService() {
473        if (mServiceState != null) {
474            // Consider the device to be in service if either voice or data service is available.
475            // Some SIM cards are marketed as data-only and do not support voice service, and on
476            // these SIM cards, we want to show signal bars for data service as well as the "no
477            // service" or "emergency calls only" text that indicates that voice is not available.
478            switch(mServiceState.getVoiceRegState()) {
479                case ServiceState.STATE_POWER_OFF:
480                    return false;
481                case ServiceState.STATE_OUT_OF_SERVICE:
482                case ServiceState.STATE_EMERGENCY_ONLY:
483                    return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
484                default:
485                    return true;
486            }
487        } else {
488            return false;
489        }
490    }
491
492    private void updateAirplaneMode() {
493        mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
494            Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
495    }
496
497    private void refreshLocale() {
498        mLocale = mContext.getResources().getConfiguration().locale;
499    }
500
501    private final void updateTelephonySignalStrength() {
502        if (!hasService()) {
503            if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
504            mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
505            mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
506            mDataSignalIconId = R.drawable.stat_sys_signal_null;
507        } else {
508            if (mSignalStrength == null) {
509                if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
510                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
511                mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
512                mDataSignalIconId = R.drawable.stat_sys_signal_null;
513                mContentDescriptionPhoneSignal = mContext.getString(
514                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
515            } else {
516                int iconLevel;
517                int[] iconList;
518                if (isCdma() && mAlwaysShowCdmaRssi) {
519                    mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
520                    if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
521                            + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
522                            + " instead of level=" + mSignalStrength.getLevel());
523                } else {
524                    mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
525                }
526
527                if (isCdma()) {
528                    if (isCdmaEri()) {
529                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
530                    } else {
531                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
532                    }
533                } else {
534                    // Though mPhone is a Manager, this call is not an IPC
535                    if (mPhone.isNetworkRoaming()) {
536                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
537                    } else {
538                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
539                    }
540                }
541                mPhoneSignalIconId = iconList[iconLevel];
542                mQSPhoneSignalIconId =
543                        TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel];
544                mContentDescriptionPhoneSignal = mContext.getString(
545                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
546                mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
547            }
548        }
549    }
550
551    private final void updateDataNetType() {
552        if (mIsWimaxEnabled && mWimaxConnected) {
553            // wimax is a special 4g network not handled by telephony
554            mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
555            mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
556            mQSDataTypeIconId = R.drawable.ic_qs_signal_4g;
557            mContentDescriptionDataType = mContext.getString(
558                    R.string.accessibility_data_connection_4g);
559        } else {
560            switch (mDataNetType) {
561                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
562                    if (!mShowAtLeastThreeGees) {
563                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
564                        mDataTypeIconId = 0;
565                        mQSDataTypeIconId = 0;
566                        mContentDescriptionDataType = mContext.getString(
567                                R.string.accessibility_data_connection_gprs);
568                        break;
569                    } else {
570                        // fall through
571                    }
572                case TelephonyManager.NETWORK_TYPE_EDGE:
573                    if (!mShowAtLeastThreeGees) {
574                        mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
575                        mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
576                        mQSDataTypeIconId = R.drawable.ic_qs_signal_e;
577                        mContentDescriptionDataType = mContext.getString(
578                                R.string.accessibility_data_connection_edge);
579                        break;
580                    } else {
581                        // fall through
582                    }
583                case TelephonyManager.NETWORK_TYPE_UMTS:
584                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
585                    mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
586                    mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
587                    mContentDescriptionDataType = mContext.getString(
588                            R.string.accessibility_data_connection_3g);
589                    break;
590                case TelephonyManager.NETWORK_TYPE_HSDPA:
591                case TelephonyManager.NETWORK_TYPE_HSUPA:
592                case TelephonyManager.NETWORK_TYPE_HSPA:
593                case TelephonyManager.NETWORK_TYPE_HSPAP:
594                    if (mHspaDataDistinguishable) {
595                        mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
596                        mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
597                        mQSDataTypeIconId = R.drawable.ic_qs_signal_h;
598                        mContentDescriptionDataType = mContext.getString(
599                                R.string.accessibility_data_connection_3_5g);
600                    } else {
601                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
602                        mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
603                        mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
604                        mContentDescriptionDataType = mContext.getString(
605                                R.string.accessibility_data_connection_3g);
606                    }
607                    break;
608                case TelephonyManager.NETWORK_TYPE_CDMA:
609                    if (!mShowAtLeastThreeGees) {
610                        // display 1xRTT for IS95A/B
611                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
612                        mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
613                        mQSDataTypeIconId = R.drawable.ic_qs_signal_1x;
614                        mContentDescriptionDataType = mContext.getString(
615                                R.string.accessibility_data_connection_cdma);
616                        break;
617                    } else {
618                        // fall through
619                    }
620                case TelephonyManager.NETWORK_TYPE_1xRTT:
621                    if (!mShowAtLeastThreeGees) {
622                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
623                        mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
624                        mQSDataTypeIconId = R.drawable.ic_qs_signal_1x;
625                        mContentDescriptionDataType = mContext.getString(
626                                R.string.accessibility_data_connection_cdma);
627                        break;
628                    } else {
629                        // fall through
630                    }
631                case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
632                case TelephonyManager.NETWORK_TYPE_EVDO_A:
633                case TelephonyManager.NETWORK_TYPE_EVDO_B:
634                case TelephonyManager.NETWORK_TYPE_EHRPD:
635                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
636                    mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
637                    mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
638                    mContentDescriptionDataType = mContext.getString(
639                            R.string.accessibility_data_connection_3g);
640                    break;
641                case TelephonyManager.NETWORK_TYPE_LTE:
642                    boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
643                    if (show4GforLTE) {
644                        mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
645                        mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
646                        mQSDataTypeIconId = R.drawable.ic_qs_signal_4g;
647                        mContentDescriptionDataType = mContext.getString(
648                                R.string.accessibility_data_connection_4g);
649                    } else {
650                        mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition];
651                        mDataTypeIconId = R.drawable.stat_sys_data_connected_lte;
652                        mQSDataTypeIconId = R.drawable.ic_qs_signal_lte;
653                        mContentDescriptionDataType = mContext.getString(
654                                R.string.accessibility_data_connection_lte);
655                    }
656                    break;
657                default:
658                    if (!mShowAtLeastThreeGees) {
659                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
660                        mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
661                        mQSDataTypeIconId = R.drawable.ic_qs_signal_g;
662                        mContentDescriptionDataType = mContext.getString(
663                                R.string.accessibility_data_connection_gprs);
664                    } else {
665                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
666                        mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
667                        mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
668                        mContentDescriptionDataType = mContext.getString(
669                                R.string.accessibility_data_connection_3g);
670                    }
671                    break;
672            }
673        }
674
675        if (isCdma()) {
676            if (isCdmaEri()) {
677                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
678                mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
679            }
680        } else if (mPhone.isNetworkRoaming()) {
681                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
682                mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
683        }
684    }
685
686    boolean isCdmaEri() {
687        if (mServiceState != null) {
688            final int iconIndex = mServiceState.getCdmaEriIconIndex();
689            if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
690                final int iconMode = mServiceState.getCdmaEriIconMode();
691                if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
692                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
693                    return true;
694                }
695            }
696        }
697        return false;
698    }
699
700    private final void updateDataIcon() {
701        int iconId;
702        boolean visible = true;
703
704        if (!isCdma()) {
705            // GSM case, we have to check also the sim state
706            if (mSimState == IccCardConstants.State.READY ||
707                    mSimState == IccCardConstants.State.UNKNOWN) {
708                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
709                    switch (mDataActivity) {
710                        case TelephonyManager.DATA_ACTIVITY_IN:
711                            iconId = mDataIconList[1];
712                            break;
713                        case TelephonyManager.DATA_ACTIVITY_OUT:
714                            iconId = mDataIconList[2];
715                            break;
716                        case TelephonyManager.DATA_ACTIVITY_INOUT:
717                            iconId = mDataIconList[3];
718                            break;
719                        default:
720                            iconId = mDataIconList[0];
721                            break;
722                    }
723                    mDataDirectionIconId = iconId;
724                } else {
725                    iconId = 0;
726                    visible = false;
727                }
728            } else {
729                iconId = R.drawable.stat_sys_no_sim;
730                visible = false; // no SIM? no data
731            }
732        } else {
733            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
734            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
735                switch (mDataActivity) {
736                    case TelephonyManager.DATA_ACTIVITY_IN:
737                        iconId = mDataIconList[1];
738                        break;
739                    case TelephonyManager.DATA_ACTIVITY_OUT:
740                        iconId = mDataIconList[2];
741                        break;
742                    case TelephonyManager.DATA_ACTIVITY_INOUT:
743                        iconId = mDataIconList[3];
744                        break;
745                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
746                    default:
747                        iconId = mDataIconList[0];
748                        break;
749                }
750            } else {
751                iconId = 0;
752                visible = false;
753            }
754        }
755
756        mDataDirectionIconId = iconId;
757        mDataConnected = visible;
758    }
759
760    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
761        if (false) {
762            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
763                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
764        }
765        StringBuilder str = new StringBuilder();
766        boolean something = false;
767        if (showPlmn && plmn != null) {
768            str.append(plmn);
769            something = true;
770        }
771        if (showSpn && spn != null) {
772            if (something) {
773                str.append(mNetworkNameSeparator);
774            }
775            str.append(spn);
776            something = true;
777        }
778        if (something) {
779            mNetworkName = str.toString();
780        } else {
781            mNetworkName = mNetworkNameDefault;
782        }
783    }
784
785    // ===== Wifi ===================================================================
786
787    class WifiHandler extends Handler {
788        @Override
789        public void handleMessage(Message msg) {
790            switch (msg.what) {
791                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
792                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
793                        mWifiChannel.sendMessage(Message.obtain(this,
794                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
795                    } else {
796                        Log.e(TAG, "Failed to connect to wifi");
797                    }
798                    break;
799                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
800                    if (msg.arg1 != mWifiActivity) {
801                        mWifiActivity = msg.arg1;
802                        refreshViews();
803                    }
804                    break;
805                default:
806                    //Ignore
807                    break;
808            }
809        }
810    }
811
812    private void updateWifiState(Intent intent) {
813        final String action = intent.getAction();
814        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
815            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
816                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
817
818        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
819            final NetworkInfo networkInfo = (NetworkInfo)
820                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
821            boolean wasConnected = mWifiConnected;
822            mWifiConnected = networkInfo != null && networkInfo.isConnected();
823            // If we just connected, grab the inintial signal strength and ssid
824            if (mWifiConnected && !wasConnected) {
825                // try getting it out of the intent first
826                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
827                if (info == null) {
828                    info = mWifiManager.getConnectionInfo();
829                }
830                if (info != null) {
831                    mWifiSsid = huntForSsid(info);
832                } else {
833                    mWifiSsid = null;
834                }
835            } else if (!mWifiConnected) {
836                mWifiSsid = null;
837            }
838        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
839            mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
840            mWifiLevel = WifiManager.calculateSignalLevel(
841                    mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
842        }
843
844        updateWifiIcons();
845    }
846
847    private void updateWifiIcons() {
848        if (mWifiConnected) {
849            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
850            mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
851            mContentDescriptionWifi = mContext.getString(
852                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
853        } else {
854            if (mDataAndWifiStacked) {
855                mWifiIconId = 0;
856                mQSWifiIconId = 0;
857            } else {
858                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
859                mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
860            }
861            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
862        }
863    }
864
865    private String huntForSsid(WifiInfo info) {
866        String ssid = info.getSSID();
867        if (ssid != null) {
868            return ssid;
869        }
870        // OK, it's not in the connectionInfo; we have to go hunting for it
871        List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
872        for (WifiConfiguration net : networks) {
873            if (net.networkId == info.getNetworkId()) {
874                return net.SSID;
875            }
876        }
877        return null;
878    }
879
880
881    // ===== Wimax ===================================================================
882    private final void updateWimaxState(Intent intent) {
883        final String action = intent.getAction();
884        boolean wasConnected = mWimaxConnected;
885        if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) {
886            int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
887                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
888            mIsWimaxEnabled = (wimaxStatus ==
889                    WimaxManagerConstants.NET_4G_STATE_ENABLED);
890        } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
891            mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
892        } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
893            mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
894                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
895            mWimaxExtraState = intent.getIntExtra(
896                    WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
897                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
898            mWimaxConnected = (mWimaxState ==
899                    WimaxManagerConstants.WIMAX_STATE_CONNECTED);
900            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
901        }
902        updateDataNetType();
903        updateWimaxIcons();
904    }
905
906    private void updateWimaxIcons() {
907        if (mIsWimaxEnabled) {
908            if (mWimaxConnected) {
909                if (mWimaxIdle)
910                    mWimaxIconId = WimaxIcons.WIMAX_IDLE;
911                else
912                    mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
913                mContentDescriptionWimax = mContext.getString(
914                        AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
915            } else {
916                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
917                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
918            }
919        } else {
920            mWimaxIconId = 0;
921        }
922    }
923
924    // ===== Full or limited Internet connectivity ==================================
925
926    private void updateConnectivity(Intent intent) {
927        if (CHATTY) {
928            Log.d(TAG, "updateConnectivity: intent=" + intent);
929        }
930
931        final ConnectivityManager connManager = (ConnectivityManager) mContext
932                .getSystemService(Context.CONNECTIVITY_SERVICE);
933        final NetworkInfo info = connManager.getActiveNetworkInfo();
934
935        // Are we connected at all, by any interface?
936        mConnected = info != null && info.isConnected();
937        if (mConnected) {
938            mConnectedNetworkType = info.getType();
939            mConnectedNetworkTypeName = info.getTypeName();
940        } else {
941            mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
942            mConnectedNetworkTypeName = null;
943        }
944
945        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
946
947        if (CHATTY) {
948            Log.d(TAG, "updateConnectivity: networkInfo=" + info);
949            Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
950        }
951
952        mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
953
954        if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
955            mBluetoothTethered = info.isConnected();
956        } else {
957            mBluetoothTethered = false;
958        }
959
960        // We want to update all the icons, all at once, for any condition change
961        updateDataNetType();
962        updateWimaxIcons();
963        updateDataIcon();
964        updateTelephonySignalStrength();
965        updateWifiIcons();
966    }
967
968
969    // ===== Update the views =======================================================
970
971    void refreshViews() {
972        Context context = mContext;
973
974        int combinedSignalIconId = 0;
975        String combinedLabel = "";
976        String wifiLabel = "";
977        String mobileLabel = "";
978        int N;
979        final boolean emergencyOnly = isEmergencyOnly();
980
981        if (!mHasMobileDataFeature) {
982            mDataSignalIconId = mPhoneSignalIconId = 0;
983            mQSPhoneSignalIconId = 0;
984            mobileLabel = "";
985        } else {
986            // We want to show the carrier name if in service and either:
987            //   - We are connected to mobile data, or
988            //   - We are not connected to mobile data, as long as the *reason* packets are not
989            //     being routed over that link is that we have better connectivity via wifi.
990            // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
991            // is connected, we show nothing.
992            // Otherwise (nothing connected) we show "No internet connection".
993
994            if (mDataConnected) {
995                mobileLabel = mNetworkName;
996            } else if (mConnected || emergencyOnly) {
997                if (hasService() || emergencyOnly) {
998                    // The isEmergencyOnly test covers the case of a phone with no SIM
999                    mobileLabel = mNetworkName;
1000                } else {
1001                    // Tablets, basically
1002                    mobileLabel = "";
1003                }
1004            } else {
1005                mobileLabel
1006                    = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1007            }
1008
1009            // Now for things that should only be shown when actually using mobile data.
1010            if (mDataConnected) {
1011                combinedSignalIconId = mDataSignalIconId;
1012
1013                combinedLabel = mobileLabel;
1014                combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
1015                mContentDescriptionCombinedSignal = mContentDescriptionDataType;
1016            }
1017        }
1018
1019        if (mWifiConnected) {
1020            if (mWifiSsid == null) {
1021                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
1022            } else {
1023                wifiLabel = mWifiSsid;
1024                if (DEBUG) {
1025                    wifiLabel += "xxxxXXXXxxxxXXXX";
1026                }
1027            }
1028
1029            combinedLabel = wifiLabel;
1030            combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
1031            mContentDescriptionCombinedSignal = mContentDescriptionWifi;
1032        } else {
1033            if (mHasMobileDataFeature) {
1034                wifiLabel = "";
1035            } else {
1036                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1037            }
1038        }
1039
1040        if (mBluetoothTethered) {
1041            combinedLabel = mContext.getString(R.string.bluetooth_tethered);
1042            combinedSignalIconId = mBluetoothTetherIconId;
1043            mContentDescriptionCombinedSignal = mContext.getString(
1044                    R.string.accessibility_bluetooth_tether);
1045        }
1046
1047        final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
1048        if (ethernetConnected) {
1049            combinedLabel = context.getString(R.string.ethernet_label);
1050        }
1051
1052        if (mAirplaneMode &&
1053                (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
1054            // Only display the flight-mode icon if not in "emergency calls only" mode.
1055
1056            // look again; your radios are now airplanes
1057            mContentDescriptionPhoneSignal = mContext.getString(
1058                    R.string.accessibility_airplane_mode);
1059            mAirplaneIconId = FLIGHT_MODE_ICON;
1060            mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
1061            mQSPhoneSignalIconId = 0;
1062
1063            // combined values from connected wifi take precedence over airplane mode
1064            if (mWifiConnected) {
1065                // Suppress "No internet connection." from mobile if wifi connected.
1066                mobileLabel = "";
1067            } else {
1068                if (mHasMobileDataFeature) {
1069                    // let the mobile icon show "No internet connection."
1070                    wifiLabel = "";
1071                } else {
1072                    wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1073                    combinedLabel = wifiLabel;
1074                }
1075                mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
1076                combinedSignalIconId = mDataSignalIconId;
1077            }
1078        }
1079        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
1080            // pretty much totally disconnected
1081
1082            combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1083            // On devices without mobile radios, we want to show the wifi icon
1084            combinedSignalIconId =
1085                mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
1086            mContentDescriptionCombinedSignal = mHasMobileDataFeature
1087                ? mContentDescriptionDataType : mContentDescriptionWifi;
1088
1089            mDataTypeIconId = 0;
1090            mQSDataTypeIconId = 0;
1091            if (isCdma()) {
1092                if (isCdmaEri()) {
1093                    mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
1094                    mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
1095                }
1096            } else if (mPhone.isNetworkRoaming()) {
1097                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
1098                mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
1099            }
1100        }
1101
1102        if (DEBUG) {
1103            Log.d(TAG, "refreshViews connected={"
1104                    + (mWifiConnected?" wifi":"")
1105                    + (mDataConnected?" data":"")
1106                    + " } level="
1107                    + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
1108                    + " combinedSignalIconId=0x"
1109                    + Integer.toHexString(combinedSignalIconId)
1110                    + "/" + getResourceName(combinedSignalIconId)
1111                    + " mobileLabel=" + mobileLabel
1112                    + " wifiLabel=" + wifiLabel
1113                    + " emergencyOnly=" + emergencyOnly
1114                    + " combinedLabel=" + combinedLabel
1115                    + " mAirplaneMode=" + mAirplaneMode
1116                    + " mDataActivity=" + mDataActivity
1117                    + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
1118                    + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId)
1119                    + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
1120                    + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
1121                    + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
1122                    + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId)
1123                    + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
1124                    + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId)
1125                    + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
1126        }
1127
1128        if (mLastPhoneSignalIconId          != mPhoneSignalIconId
1129         || mLastWifiIconId                 != mWifiIconId
1130         || mLastWimaxIconId                != mWimaxIconId
1131         || mLastDataTypeIconId             != mDataTypeIconId
1132         || mLastAirplaneMode               != mAirplaneMode
1133         || mLastLocale                     != mLocale)
1134        {
1135            // NB: the mLast*s will be updated later
1136            for (SignalCluster cluster : mSignalClusters) {
1137                refreshSignalCluster(cluster);
1138            }
1139            for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
1140                notifySignalsChangedCallbacks(cb);
1141            }
1142        }
1143
1144        if (mLastAirplaneMode != mAirplaneMode) {
1145            mLastAirplaneMode = mAirplaneMode;
1146        }
1147
1148        if (mLastLocale != mLocale) {
1149            mLastLocale = mLocale;
1150        }
1151
1152        // the phone icon on phones
1153        if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
1154            mLastPhoneSignalIconId = mPhoneSignalIconId;
1155        }
1156
1157        // the data icon on phones
1158        if (mLastDataDirectionIconId != mDataDirectionIconId) {
1159            mLastDataDirectionIconId = mDataDirectionIconId;
1160        }
1161
1162        // the wifi icon on phones
1163        if (mLastWifiIconId != mWifiIconId) {
1164            mLastWifiIconId = mWifiIconId;
1165        }
1166
1167        // the wimax icon on phones
1168        if (mLastWimaxIconId != mWimaxIconId) {
1169            mLastWimaxIconId = mWimaxIconId;
1170        }
1171        // the combined data signal icon
1172        if (mLastCombinedSignalIconId != combinedSignalIconId) {
1173            mLastCombinedSignalIconId = combinedSignalIconId;
1174        }
1175
1176        // the data network type overlay
1177        if (mLastDataTypeIconId != mDataTypeIconId) {
1178            mLastDataTypeIconId = mDataTypeIconId;
1179        }
1180
1181        // the combinedLabel in the notification panel
1182        if (!mLastCombinedLabel.equals(combinedLabel)) {
1183            mLastCombinedLabel = combinedLabel;
1184            N = mCombinedLabelViews.size();
1185            for (int i=0; i<N; i++) {
1186                TextView v = mCombinedLabelViews.get(i);
1187                v.setText(combinedLabel);
1188            }
1189        }
1190
1191        // wifi label
1192        N = mWifiLabelViews.size();
1193        for (int i=0; i<N; i++) {
1194            TextView v = mWifiLabelViews.get(i);
1195            v.setText(wifiLabel);
1196            if ("".equals(wifiLabel)) {
1197                v.setVisibility(View.GONE);
1198            } else {
1199                v.setVisibility(View.VISIBLE);
1200            }
1201        }
1202
1203        // mobile label
1204        N = mMobileLabelViews.size();
1205        for (int i=0; i<N; i++) {
1206            TextView v = mMobileLabelViews.get(i);
1207            v.setText(mobileLabel);
1208            if ("".equals(mobileLabel)) {
1209                v.setVisibility(View.GONE);
1210            } else {
1211                v.setVisibility(View.VISIBLE);
1212            }
1213        }
1214
1215        // e-call label
1216        N = mEmergencyLabelViews.size();
1217        for (int i=0; i<N; i++) {
1218            TextView v = mEmergencyLabelViews.get(i);
1219            if (!emergencyOnly) {
1220                v.setVisibility(View.GONE);
1221            } else {
1222                v.setText(mobileLabel); // comes from the telephony stack
1223                v.setVisibility(View.VISIBLE);
1224            }
1225        }
1226    }
1227
1228    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1229        pw.println("NetworkController state:");
1230        pw.println(String.format("  %s network type %d (%s)",
1231                mConnected?"CONNECTED":"DISCONNECTED",
1232                mConnectedNetworkType, mConnectedNetworkTypeName));
1233        pw.println("  - telephony ------");
1234        pw.print("  hasVoiceCallingFeature()=");
1235        pw.println(hasVoiceCallingFeature());
1236        pw.print("  hasService()=");
1237        pw.println(hasService());
1238        pw.print("  mHspaDataDistinguishable=");
1239        pw.println(mHspaDataDistinguishable);
1240        pw.print("  mDataConnected=");
1241        pw.println(mDataConnected);
1242        pw.print("  mSimState=");
1243        pw.println(mSimState);
1244        pw.print("  mPhoneState=");
1245        pw.println(mPhoneState);
1246        pw.print("  mDataState=");
1247        pw.println(mDataState);
1248        pw.print("  mDataActivity=");
1249        pw.println(mDataActivity);
1250        pw.print("  mDataNetType=");
1251        pw.print(mDataNetType);
1252        pw.print("/");
1253        pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
1254        pw.print("  mServiceState=");
1255        pw.println(mServiceState);
1256        pw.print("  mSignalStrength=");
1257        pw.println(mSignalStrength);
1258        pw.print("  mLastSignalLevel=");
1259        pw.println(mLastSignalLevel);
1260        pw.print("  mNetworkName=");
1261        pw.println(mNetworkName);
1262        pw.print("  mNetworkNameDefault=");
1263        pw.println(mNetworkNameDefault);
1264        pw.print("  mNetworkNameSeparator=");
1265        pw.println(mNetworkNameSeparator.replace("\n","\\n"));
1266        pw.print("  mPhoneSignalIconId=0x");
1267        pw.print(Integer.toHexString(mPhoneSignalIconId));
1268        pw.print("/");
1269        pw.print("  mQSPhoneSignalIconId=0x");
1270        pw.print(Integer.toHexString(mQSPhoneSignalIconId));
1271        pw.print("/");
1272        pw.println(getResourceName(mPhoneSignalIconId));
1273        pw.print("  mDataDirectionIconId=");
1274        pw.print(Integer.toHexString(mDataDirectionIconId));
1275        pw.print("/");
1276        pw.println(getResourceName(mDataDirectionIconId));
1277        pw.print("  mDataSignalIconId=");
1278        pw.print(Integer.toHexString(mDataSignalIconId));
1279        pw.print("/");
1280        pw.println(getResourceName(mDataSignalIconId));
1281        pw.print("  mDataTypeIconId=");
1282        pw.print(Integer.toHexString(mDataTypeIconId));
1283        pw.print("/");
1284        pw.println(getResourceName(mDataTypeIconId));
1285        pw.print("  mQSDataTypeIconId=");
1286        pw.print(Integer.toHexString(mQSDataTypeIconId));
1287        pw.print("/");
1288        pw.println(getResourceName(mQSDataTypeIconId));
1289
1290        pw.println("  - wifi ------");
1291        pw.print("  mWifiEnabled=");
1292        pw.println(mWifiEnabled);
1293        pw.print("  mWifiConnected=");
1294        pw.println(mWifiConnected);
1295        pw.print("  mWifiRssi=");
1296        pw.println(mWifiRssi);
1297        pw.print("  mWifiLevel=");
1298        pw.println(mWifiLevel);
1299        pw.print("  mWifiSsid=");
1300        pw.println(mWifiSsid);
1301        pw.println(String.format("  mWifiIconId=0x%08x/%s",
1302                    mWifiIconId, getResourceName(mWifiIconId)));
1303        pw.println(String.format("  mQSWifiIconId=0x%08x/%s",
1304                    mQSWifiIconId, getResourceName(mQSWifiIconId)));
1305        pw.print("  mWifiActivity=");
1306        pw.println(mWifiActivity);
1307
1308        if (mWimaxSupported) {
1309            pw.println("  - wimax ------");
1310            pw.print("  mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
1311            pw.print("  mWimaxConnected="); pw.println(mWimaxConnected);
1312            pw.print("  mWimaxIdle="); pw.println(mWimaxIdle);
1313            pw.println(String.format("  mWimaxIconId=0x%08x/%s",
1314                        mWimaxIconId, getResourceName(mWimaxIconId)));
1315            pw.println(String.format("  mWimaxSignal=%d", mWimaxSignal));
1316            pw.println(String.format("  mWimaxState=%d", mWimaxState));
1317            pw.println(String.format("  mWimaxExtraState=%d", mWimaxExtraState));
1318        }
1319
1320        pw.println("  - Bluetooth ----");
1321        pw.print("  mBtReverseTethered=");
1322        pw.println(mBluetoothTethered);
1323
1324        pw.println("  - connectivity ------");
1325        pw.print("  mInetCondition=");
1326        pw.println(mInetCondition);
1327
1328        pw.println("  - icons ------");
1329        pw.print("  mLastPhoneSignalIconId=0x");
1330        pw.print(Integer.toHexString(mLastPhoneSignalIconId));
1331        pw.print("/");
1332        pw.println(getResourceName(mLastPhoneSignalIconId));
1333        pw.print("  mLastDataDirectionIconId=0x");
1334        pw.print(Integer.toHexString(mLastDataDirectionIconId));
1335        pw.print("/");
1336        pw.println(getResourceName(mLastDataDirectionIconId));
1337        pw.print("  mLastWifiIconId=0x");
1338        pw.print(Integer.toHexString(mLastWifiIconId));
1339        pw.print("/");
1340        pw.println(getResourceName(mLastWifiIconId));
1341        pw.print("  mLastCombinedSignalIconId=0x");
1342        pw.print(Integer.toHexString(mLastCombinedSignalIconId));
1343        pw.print("/");
1344        pw.println(getResourceName(mLastCombinedSignalIconId));
1345        pw.print("  mLastDataTypeIconId=0x");
1346        pw.print(Integer.toHexString(mLastDataTypeIconId));
1347        pw.print("/");
1348        pw.println(getResourceName(mLastDataTypeIconId));
1349        pw.print("  mLastCombinedLabel=");
1350        pw.print(mLastCombinedLabel);
1351        pw.println("");
1352    }
1353
1354    private String getResourceName(int resId) {
1355        if (resId != 0) {
1356            final Resources res = mContext.getResources();
1357            try {
1358                return res.getResourceName(resId);
1359            } catch (android.content.res.Resources.NotFoundException ex) {
1360                return "(unknown)";
1361            }
1362        } else {
1363            return "(null)";
1364        }
1365    }
1366
1367    private boolean mDemoMode;
1368    private int mDemoInetCondition;
1369    private int mDemoWifiLevel;
1370    private int mDemoDataTypeIconId;
1371    private int mDemoMobileLevel;
1372
1373    @Override
1374    public void dispatchDemoCommand(String command, Bundle args) {
1375        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
1376            mDemoMode = true;
1377            mDemoWifiLevel = mWifiLevel;
1378            mDemoInetCondition = mInetCondition;
1379            mDemoDataTypeIconId = mDataTypeIconId;
1380            mDemoMobileLevel = mLastSignalLevel;
1381        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
1382            mDemoMode = false;
1383            for (SignalCluster cluster : mSignalClusters) {
1384                refreshSignalCluster(cluster);
1385            }
1386        } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
1387            String airplane = args.getString("airplane");
1388            if (airplane != null) {
1389                boolean show = airplane.equals("show");
1390                for (SignalCluster cluster : mSignalClusters) {
1391                    cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON);
1392                }
1393            }
1394            String fully = args.getString("fully");
1395            if (fully != null) {
1396                mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
1397            }
1398            String wifi = args.getString("wifi");
1399            if (wifi != null) {
1400                boolean show = wifi.equals("show");
1401                String level = args.getString("level");
1402                if (level != null) {
1403                    mDemoWifiLevel = level.equals("null") ? -1
1404                            : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
1405                }
1406                int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null
1407                        : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
1408                for (SignalCluster cluster : mSignalClusters) {
1409                    cluster.setWifiIndicators(
1410                            show,
1411                            iconId,
1412                            "Demo");
1413                }
1414            }
1415            String mobile = args.getString("mobile");
1416            if (mobile != null) {
1417                boolean show = mobile.equals("show");
1418                String datatype = args.getString("datatype");
1419                if (datatype != null) {
1420                    mDemoDataTypeIconId =
1421                            datatype.equals("1x") ? R.drawable.stat_sys_data_connected_1x :
1422                            datatype.equals("3g") ? R.drawable.stat_sys_data_connected_3g :
1423                            datatype.equals("4g") ? R.drawable.stat_sys_data_connected_4g :
1424                            datatype.equals("e") ? R.drawable.stat_sys_data_connected_e :
1425                            datatype.equals("g") ? R.drawable.stat_sys_data_connected_g :
1426                            datatype.equals("h") ? R.drawable.stat_sys_data_connected_h :
1427                            datatype.equals("lte") ? R.drawable.stat_sys_data_connected_lte :
1428                            datatype.equals("roam") ? R.drawable.stat_sys_data_connected_roam :
1429                            0;
1430                }
1431                int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
1432                String level = args.getString("level");
1433                if (level != null) {
1434                    mDemoMobileLevel = level.equals("null") ? -1
1435                            : Math.min(Integer.parseInt(level), icons[0].length - 1);
1436                }
1437                int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null :
1438                        icons[mDemoInetCondition][mDemoMobileLevel];
1439                for (SignalCluster cluster : mSignalClusters) {
1440                    cluster.setMobileDataIndicators(
1441                            show,
1442                            iconId,
1443                            mDemoDataTypeIconId,
1444                            "Demo",
1445                            "Demo");
1446                }
1447            }
1448        }
1449    }
1450}
1451