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