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