NetworkController.java revision 2b8bcfe5b74e1a34d136f4ff46e3c94397f38f82
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.SupplicantState;
32import android.net.wifi.WifiConfiguration;
33import android.net.wifi.WifiInfo;
34import android.net.wifi.WifiManager;
35import android.os.Binder;
36import android.os.Handler;
37import android.os.HandlerThread;
38import android.os.Looper;
39import android.os.Message;
40import android.os.Messenger;
41import android.os.RemoteException;
42import android.provider.Settings;
43import android.provider.Telephony;
44import android.telephony.PhoneStateListener;
45import android.telephony.ServiceState;
46import android.telephony.SignalStrength;
47import android.telephony.TelephonyManager;
48import android.util.Slog;
49import android.view.View;
50import android.widget.ImageView;
51import android.widget.TextView;
52
53import com.android.internal.app.IBatteryStats;
54import com.android.internal.telephony.IccCard;
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
67    // telephony
68    boolean mHspaDataDistinguishable;
69    final TelephonyManager mPhone;
70    boolean mDataConnected;
71    IccCard.State mSimState = IccCard.State.READY;
72    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
73    int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
74    int mDataState = TelephonyManager.DATA_DISCONNECTED;
75    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
76    ServiceState mServiceState;
77    SignalStrength mSignalStrength;
78    int[] mDataIconList = TelephonyIcons.DATA_G[0];
79    String mNetworkName;
80    String mNetworkNameDefault;
81    String mNetworkNameSeparator;
82    int mPhoneSignalIconId;
83    int mDataDirectionIconId;
84    int mDataDirectionOverlayIconId;
85    int mDataSignalIconId;
86    int mDataTypeIconId;
87    boolean mDataActive;
88
89    // wifi
90    final WifiManager mWifiManager;
91    AsyncChannel mWifiChannel;
92    boolean mWifiEnabled, mWifiConnected;
93    int mWifiLevel;
94    String mWifiSsid;
95    int mWifiIconId;
96
97    // bluetooth
98    private boolean mBluetoothTethered = false;
99    private int mBluetoothTetherIconId =
100        com.android.internal.R.drawable.stat_sys_tether_bluetooth;
101
102    // data connectivity (regardless of state, can we access the internet?)
103    // state of inet connection - 0 not connected, 100 connected
104    private int mInetCondition = 0;
105    private static final int INET_CONDITION_THRESHOLD = 50;
106
107    // our ui
108    Context mContext;
109    ArrayList<ImageView> mPhoneSignalIconViews = new ArrayList<ImageView>();
110    ArrayList<ImageView> mDataDirectionIconViews = new ArrayList<ImageView>();
111    ArrayList<ImageView> mDataDirectionOverlayIconViews = new ArrayList<ImageView>();
112    ArrayList<ImageView> mWifiIconViews = new ArrayList<ImageView>();
113    ArrayList<ImageView> mCombinedSignalIconViews = new ArrayList<ImageView>();
114    ArrayList<ImageView> mDataTypeIconViews = new ArrayList<ImageView>();
115    ArrayList<TextView> mLabelViews = new ArrayList<TextView>();
116    int mLastPhoneSignalIconId = -1;
117    int mLastDataDirectionIconId = -1;
118    int mLastDataDirectionOverlayIconId = -1;
119    int mLastWifiIconId = -1;
120    int mLastCombinedSignalIconId = -1;
121    int mLastDataTypeIconId = -1;
122    String mLastLabel = "";
123
124    // yuck -- stop doing this here and put it in the framework
125    IBatteryStats mBatteryStats;
126
127    /**
128     * Construct this controller object and register for updates.
129     */
130    public NetworkController(Context context) {
131        mContext = context;
132
133        // telephony
134        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
135        mPhone.listen(mPhoneStateListener,
136                          PhoneStateListener.LISTEN_SERVICE_STATE
137                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
138                        | PhoneStateListener.LISTEN_CALL_STATE
139                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
140                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
141        mHspaDataDistinguishable = mContext.getResources().getBoolean(
142                R.bool.config_hspa_data_distinguishable);
143        mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
144        mNetworkNameDefault = mContext.getString(
145                com.android.internal.R.string.lockscreen_carrier_default);
146        mNetworkName = mNetworkNameDefault;
147
148        // wifi
149        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
150        HandlerThread handlerThread = new HandlerThread("WifiServiceThread");
151        handlerThread.start();
152        Handler handler = new WifiHandler(handlerThread.getLooper());
153        mWifiChannel = new AsyncChannel();
154        Messenger wifiMessenger = mWifiManager.getMessenger();
155        if (wifiMessenger != null) {
156            mWifiChannel.connect(mContext, handler, wifiMessenger);
157        }
158
159        // broadcasts
160        IntentFilter filter = new IntentFilter();
161        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
162        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
163        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
164        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
165        filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION);
166        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
167        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
168        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
169        context.registerReceiver(this, filter);
170
171        // yuck
172        mBatteryStats = BatteryStatsService.getService();
173    }
174
175    public void addPhoneSignalIconView(ImageView v) {
176        mPhoneSignalIconViews.add(v);
177    }
178
179    public void addDataDirectionIconView(ImageView v) {
180        mDataDirectionIconViews.add(v);
181    }
182
183    public void addDataDirectionOverlayIconView(ImageView v) {
184        mDataDirectionOverlayIconViews.add(v);
185    }
186
187    public void addWifiIconView(ImageView v) {
188        mWifiIconViews.add(v);
189    }
190
191    public void addCombinedSignalIconView(ImageView v) {
192        mCombinedSignalIconViews.add(v);
193    }
194
195    public void addDataTypeIconView(ImageView v) {
196        mDataTypeIconViews.add(v);
197    }
198
199    public void addLabelView(TextView v) {
200        mLabelViews.add(v);
201    }
202
203    @Override
204    public void onReceive(Context context, Intent intent) {
205        final String action = intent.getAction();
206        if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
207                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
208                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
209            updateWifiState(intent);
210            refreshViews();
211        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
212            updateSimState(intent);
213            updateDataIcon();
214            refreshViews();
215        } else if (action.equals(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION)) {
216            updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
217                        intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
218                        intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
219                        intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
220            refreshViews();
221        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
222                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
223            updateConnectivity(intent);
224            refreshViews();
225        } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
226            refreshViews();
227        }
228    }
229
230
231    // ===== Telephony ==============================================================
232
233    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
234        @Override
235        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
236            if (DEBUG) {
237                Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength);
238            }
239            mSignalStrength = signalStrength;
240            updateTelephonySignalStrength();
241            refreshViews();
242        }
243
244        @Override
245        public void onServiceStateChanged(ServiceState state) {
246            if (DEBUG) {
247                Slog.d(TAG, "onServiceStateChanged state=" + state.getState());
248            }
249            mServiceState = state;
250            updateTelephonySignalStrength();
251            updateDataIcon();
252            refreshViews();
253        }
254
255        @Override
256        public void onCallStateChanged(int state, String incomingNumber) {
257            if (DEBUG) {
258                Slog.d(TAG, "onCallStateChanged state=" + state);
259            }
260            // In cdma, if a voice call is made, RSSI should switch to 1x.
261            if (isCdma()) {
262                updateTelephonySignalStrength();
263                refreshViews();
264            }
265        }
266
267        @Override
268        public void onDataConnectionStateChanged(int state, int networkType) {
269            if (DEBUG) {
270                Slog.d(TAG, "onDataConnectionStateChanged: state=" + state
271                        + " type=" + networkType);
272            }
273            mDataState = state;
274            mDataNetType = networkType;
275            updateDataNetType();
276            updateDataIcon();
277            refreshViews();
278        }
279
280        @Override
281        public void onDataActivity(int direction) {
282            if (DEBUG) {
283                Slog.d(TAG, "onDataActivity: direction=" + direction);
284            }
285            mDataActivity = direction;
286            updateDataIcon();
287            refreshViews();
288        }
289    };
290
291    private final void updateSimState(Intent intent) {
292        String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
293        if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
294            mSimState = IccCard.State.ABSENT;
295        }
296        else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
297            mSimState = IccCard.State.READY;
298        }
299        else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
300            final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
301            if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
302                mSimState = IccCard.State.PIN_REQUIRED;
303            }
304            else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
305                mSimState = IccCard.State.PUK_REQUIRED;
306            }
307            else {
308                mSimState = IccCard.State.NETWORK_LOCKED;
309            }
310        } else {
311            mSimState = IccCard.State.UNKNOWN;
312        }
313    }
314
315    private boolean isCdma() {
316        return (mSignalStrength != null) && !mSignalStrength.isGsm();
317    }
318
319    private boolean hasService() {
320        if (mServiceState != null) {
321            switch (mServiceState.getState()) {
322                case ServiceState.STATE_OUT_OF_SERVICE:
323                case ServiceState.STATE_POWER_OFF:
324                    return false;
325                default:
326                    return true;
327            }
328        } else {
329            return false;
330        }
331    }
332
333    private final void updateTelephonySignalStrength() {
334        // Display signal strength while in "emergency calls only" mode
335        if (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly())) {
336            //Slog.d(TAG, "updateTelephonySignalStrength: no service");
337            if (Settings.System.getInt(mContext.getContentResolver(),
338                    Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
339                mPhoneSignalIconId = R.drawable.stat_sys_signal_flightmode;
340                mDataSignalIconId = R.drawable.stat_sys_signal_flightmode;
341            } else {
342                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
343                mDataSignalIconId = R.drawable.stat_sys_signal_0; // note we use 0 instead of null
344            }
345        } else {
346            if (mSignalStrength == null) {
347                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
348                mDataSignalIconId = R.drawable.stat_sys_signal_0; // note we use 0 instead of null
349            } else {
350                int iconLevel;
351                int[] iconList;
352                iconLevel = mSignalStrength.getLevel();
353                if (isCdma()) {
354                    if (isCdmaEri()) {
355                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
356                    } else {
357                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
358                    }
359                } else {
360                    // Though mPhone is a Manager, this call is not an IPC
361                    if (mPhone.isNetworkRoaming()) {
362                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
363                    } else {
364                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
365                    }
366                }
367                mPhoneSignalIconId = iconList[iconLevel];
368                mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
369            }
370        }
371    }
372
373    private final void updateDataNetType() {
374        switch (mDataNetType) {
375            case TelephonyManager.NETWORK_TYPE_UNKNOWN:
376                mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
377                mDataTypeIconId = 0;
378                break;
379            case TelephonyManager.NETWORK_TYPE_EDGE:
380                mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
381                mDataTypeIconId = R.drawable.stat_sys_signal_edge;
382                break;
383            case TelephonyManager.NETWORK_TYPE_UMTS:
384                mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
385                mDataTypeIconId = R.drawable.stat_sys_signal_3g;
386                break;
387            case TelephonyManager.NETWORK_TYPE_HSDPA:
388            case TelephonyManager.NETWORK_TYPE_HSUPA:
389            case TelephonyManager.NETWORK_TYPE_HSPA:
390                if (mHspaDataDistinguishable) {
391                    mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
392                    mDataTypeIconId = R.drawable.stat_sys_signal_hsdpa;
393                } else {
394                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
395                    mDataTypeIconId = R.drawable.stat_sys_signal_3g;
396                }
397                break;
398            case TelephonyManager.NETWORK_TYPE_CDMA:
399                // display 1xRTT for IS95A/B
400                mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
401                mDataTypeIconId = R.drawable.stat_sys_signal_1x;
402                break;
403            case TelephonyManager.NETWORK_TYPE_1xRTT:
404                mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
405                mDataTypeIconId = R.drawable.stat_sys_signal_1x;
406                break;
407            case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
408            case TelephonyManager.NETWORK_TYPE_EVDO_A:
409            case TelephonyManager.NETWORK_TYPE_EVDO_B:
410            case TelephonyManager.NETWORK_TYPE_EHRPD:
411                mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
412                mDataTypeIconId = R.drawable.stat_sys_signal_3g;
413                break;
414            case TelephonyManager.NETWORK_TYPE_LTE:
415                mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
416                mDataTypeIconId = R.drawable.stat_sys_signal_4g;
417                break;
418            default:
419                mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
420                mDataTypeIconId = R.drawable.stat_sys_signal_gprs;
421                break;
422        }
423        if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
424            mDataTypeIconId = R.drawable.stat_sys_signal_roam;
425        }
426    }
427
428    boolean isCdmaEri() {
429        final int iconIndex = mServiceState.getCdmaEriIconIndex();
430        if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
431            final int iconMode = mServiceState.getCdmaEriIconMode();
432            if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
433                    || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
434                return true;
435            }
436        }
437        return false;
438    }
439
440    private final void updateDataIcon() {
441        int iconId;
442        boolean visible = true;
443
444        if (!isCdma()) {
445            // GSM case, we have to check also the sim state
446            if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
447                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
448                    switch (mDataActivity) {
449                        case TelephonyManager.DATA_ACTIVITY_IN:
450                            iconId = mDataIconList[1];
451                            break;
452                        case TelephonyManager.DATA_ACTIVITY_OUT:
453                            iconId = mDataIconList[2];
454                            break;
455                        case TelephonyManager.DATA_ACTIVITY_INOUT:
456                            iconId = mDataIconList[3];
457                            break;
458                        default:
459                            iconId = mDataIconList[0];
460                            break;
461                    }
462                    mDataDirectionIconId = iconId;
463                } else {
464                    iconId = 0;
465                    visible = false;
466                }
467            } else {
468                iconId = R.drawable.stat_sys_no_sim;
469            }
470        } else {
471            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
472            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
473                switch (mDataActivity) {
474                    case TelephonyManager.DATA_ACTIVITY_IN:
475                        iconId = mDataIconList[1];
476                        break;
477                    case TelephonyManager.DATA_ACTIVITY_OUT:
478                        iconId = mDataIconList[2];
479                        break;
480                    case TelephonyManager.DATA_ACTIVITY_INOUT:
481                        iconId = mDataIconList[3];
482                        break;
483                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
484                    default:
485                        iconId = mDataIconList[0];
486                        break;
487                }
488            } else {
489                iconId = 0;
490                visible = false;
491            }
492        }
493
494        // yuck - this should NOT be done by the status bar
495        long ident = Binder.clearCallingIdentity();
496        try {
497            mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
498        } catch (RemoteException e) {
499        } finally {
500            Binder.restoreCallingIdentity(ident);
501        }
502
503        mDataDirectionIconId = iconId;
504        mDataConnected = visible;
505    }
506
507    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
508        if (false) {
509            Slog.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
510                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
511        }
512        StringBuilder str = new StringBuilder();
513        boolean something = false;
514        if (showPlmn && plmn != null) {
515            str.append(plmn);
516            something = true;
517        }
518        if (showSpn && spn != null) {
519            if (something) {
520                str.append(mNetworkNameSeparator);
521            }
522            str.append(spn);
523            something = true;
524        }
525        if (something) {
526            mNetworkName = str.toString();
527        } else {
528            mNetworkName = mNetworkNameDefault;
529        }
530    }
531
532    // ===== Wifi ===================================================================
533
534    class WifiHandler extends Handler {
535
536        WifiHandler(Looper looper) {
537            super(looper);
538        }
539
540        @Override
541        public void handleMessage(Message msg) {
542            switch (msg.what) {
543                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
544                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
545                        mWifiChannel.sendMessage(Message.obtain(this,
546                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
547                    } else {
548                        Slog.e(TAG, "Failed to connect to wifi");
549                    }
550                    break;
551                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
552                    int dataActivity = msg.arg1;
553                    /* TODO: update icons based on data activity */
554                    switch (dataActivity) {
555                        case WifiManager.DATA_ACTIVITY_IN:
556                            break;
557                        case WifiManager.DATA_ACTIVITY_OUT:
558                            break;
559                        case WifiManager.DATA_ACTIVITY_INOUT:
560                            break;
561                        case WifiManager.DATA_ACTIVITY_NONE:
562                            break;
563                    }
564                    break;
565                default:
566                    //Ignore
567                    break;
568            }
569        }
570    }
571
572    private void updateWifiState(Intent intent) {
573        final String action = intent.getAction();
574        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
575            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
576                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
577
578        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
579            final NetworkInfo networkInfo = (NetworkInfo)
580                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
581            boolean wasConnected = mWifiConnected;
582            mWifiConnected = networkInfo != null && networkInfo.isConnected();
583            // If we just connected, grab the inintial signal strength and ssid
584            if (mWifiConnected && !wasConnected) {
585                WifiInfo info = mWifiManager.getConnectionInfo();
586                if (info != null) {
587                    mWifiLevel = WifiManager.calculateSignalLevel(info.getRssi(),
588                            WifiIcons.WIFI_LEVEL_COUNT);
589                    mWifiSsid = huntForSsid(info);
590                } else {
591                    mWifiLevel = 0;
592                    mWifiSsid = null;
593                }
594            } else if (!mWifiConnected) {
595                mWifiLevel = 0;
596                mWifiSsid = null;
597            }
598
599        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
600            if (mWifiConnected) {
601                final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
602                mWifiLevel = WifiManager.calculateSignalLevel(newRssi, WifiIcons.WIFI_LEVEL_COUNT);
603            }
604        }
605
606        updateWifiIcons();
607    }
608
609    private void updateWifiIcons() {
610        if (mWifiConnected) {
611            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
612        } else {
613            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[0][0];
614        }
615    }
616
617    private String huntForSsid(WifiInfo info) {
618        String ssid = info.getSSID();
619        if (ssid != null) {
620            return ssid;
621        }
622        // OK, it's not in the connectionInfo; we have to go hunting for it
623        List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
624        for (WifiConfiguration net : networks) {
625            if (net.networkId == info.getNetworkId()) {
626                return net.SSID;
627            }
628        }
629        return null;
630    }
631
632
633    // ===== Full or limited Internet connectivity ==================================
634
635    private void updateConnectivity(Intent intent) {
636        NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra(
637                ConnectivityManager.EXTRA_NETWORK_INFO));
638        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
639
640        int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
641
642        switch (info.getType()) {
643            case ConnectivityManager.TYPE_MOBILE:
644                mInetCondition = inetCondition;
645                updateDataNetType();
646                updateDataIcon();
647                updateTelephonySignalStrength(); // apply any change in connectionStatus
648                break;
649            case ConnectivityManager.TYPE_WIFI:
650                mInetCondition = inetCondition;
651                updateWifiIcons();
652                break;
653            case ConnectivityManager.TYPE_BLUETOOTH:
654                mInetCondition = inetCondition;
655                if (info != null) {
656                    mBluetoothTethered = info.isConnected() ? true: false;
657                } else {
658                    mBluetoothTethered = false;
659                }
660                break;
661        }
662    }
663
664
665    // ===== Update the views =======================================================
666
667    // figure out what to show- there should be one connected network or nothing
668    // General order of preference is: wifi, 3G than bluetooth. This might vary by product.
669    void refreshViews() {
670        Context context = mContext;
671
672        int combinedSignalIconId;
673        int dataDirectionOverlayIconId = 0;
674        int dataTypeIconId;
675        String label;
676        int N;
677
678        if (mWifiConnected) {
679            if (mWifiSsid == null) {
680                label = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
681            } else {
682                label = mWifiSsid;
683            }
684            combinedSignalIconId = mWifiIconId;
685            dataTypeIconId = 0;
686        } else if (mDataConnected) {
687            label = mNetworkName;
688            combinedSignalIconId = mDataSignalIconId;
689            switch (mDataActivity) {
690                case TelephonyManager.DATA_ACTIVITY_IN:
691                    dataDirectionOverlayIconId = R.drawable.stat_sys_signal_in;
692                    break;
693                case TelephonyManager.DATA_ACTIVITY_OUT:
694                    dataDirectionOverlayIconId = R.drawable.stat_sys_signal_out;
695                    break;
696                case TelephonyManager.DATA_ACTIVITY_INOUT:
697                    dataDirectionOverlayIconId = R.drawable.stat_sys_signal_inout;
698                    break;
699                default:
700                    dataDirectionOverlayIconId = 0;
701                    break;
702            }
703            combinedSignalIconId = mDataSignalIconId;
704            dataTypeIconId = mDataTypeIconId;
705        } else if (mBluetoothTethered) {
706            label = mContext.getString(R.string.bluetooth_tethered);
707            combinedSignalIconId = mBluetoothTetherIconId;
708            dataTypeIconId = 0;
709        } else {
710            label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
711            combinedSignalIconId = mDataSignalIconId;
712            dataTypeIconId = 0;
713        }
714
715        if (false) {
716            Slog.d(TAG, "refreshViews combinedSignalIconId=0x"
717                    + Integer.toHexString(combinedSignalIconId)
718                    + "/" + getResourceName(combinedSignalIconId)
719                    + " dataDirectionOverlayIconId=0x" + Integer.toHexString(dataDirectionOverlayIconId)
720                    + " mDataActivity=" + mDataActivity
721                    + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
722                    + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
723                    + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
724                    + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
725                    + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
726                    + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
727        }
728
729        // the phone icon on phones
730        if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
731            mLastPhoneSignalIconId = mPhoneSignalIconId;
732            N = mPhoneSignalIconViews.size();
733            for (int i=0; i<N; i++) {
734                final ImageView v = mPhoneSignalIconViews.get(i);
735                v.setImageResource(mPhoneSignalIconId);
736            }
737        }
738
739        // the data icon on phones
740        if (mLastDataDirectionIconId != mDataDirectionIconId) {
741            mLastDataDirectionIconId = mDataDirectionIconId;
742            N = mDataDirectionIconViews.size();
743            for (int i=0; i<N; i++) {
744                final ImageView v = mDataDirectionIconViews.get(i);
745                v.setImageResource(mDataDirectionIconId);
746            }
747        }
748
749        // the wifi icon on phones
750        if (mLastWifiIconId != mWifiIconId) {
751            mLastWifiIconId = mWifiIconId;
752            N = mWifiIconViews.size();
753            for (int i=0; i<N; i++) {
754                final ImageView v = mWifiIconViews.get(i);
755                v.setImageResource(mWifiIconId);
756            }
757        }
758
759        // the combined data signal icon
760        if (mLastCombinedSignalIconId != combinedSignalIconId) {
761            mLastCombinedSignalIconId = combinedSignalIconId;
762            N = mCombinedSignalIconViews.size();
763            for (int i=0; i<N; i++) {
764                final ImageView v = mCombinedSignalIconViews.get(i);
765                v.setImageResource(combinedSignalIconId);
766            }
767        }
768
769        // the data network type overlay
770        if (mLastDataTypeIconId != dataTypeIconId) {
771            mLastDataTypeIconId = dataTypeIconId;
772            N = mDataTypeIconViews.size();
773            for (int i=0; i<N; i++) {
774                final ImageView v = mDataTypeIconViews.get(i);
775                if (dataTypeIconId == 0) {
776                    v.setVisibility(View.INVISIBLE);
777                } else {
778                    v.setVisibility(View.VISIBLE);
779                    v.setImageResource(dataTypeIconId);
780                }
781            }
782        }
783
784        // the data direction overlay
785        if (mLastDataDirectionOverlayIconId != dataDirectionOverlayIconId) {
786            Slog.d(TAG, "changing data overlay icon id to " + dataDirectionOverlayIconId);
787            mLastDataDirectionOverlayIconId = dataDirectionOverlayIconId;
788            N = mDataDirectionOverlayIconViews.size();
789            for (int i=0; i<N; i++) {
790                final ImageView v = mDataDirectionOverlayIconViews.get(i);
791                if (dataDirectionOverlayIconId == 0) {
792                    v.setVisibility(View.INVISIBLE);
793                } else {
794                    v.setVisibility(View.VISIBLE);
795                    v.setImageResource(dataDirectionOverlayIconId);
796                }
797            }
798        }
799
800        // the label in the notification panel
801        if (!mLastLabel.equals(label)) {
802            mLastLabel = label;
803            N = mLabelViews.size();
804            for (int i=0; i<N; i++) {
805                TextView v = mLabelViews.get(i);
806                v.setText(label);
807            }
808        }
809    }
810
811    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
812        pw.println("  - telephony ------");
813        pw.print("  mHspaDataDistinguishable=");
814        pw.println(mHspaDataDistinguishable);
815        pw.print("  mDataConnected=");
816        pw.println(mDataConnected);
817        pw.print("  mSimState=");
818        pw.println(mSimState);
819        pw.print("  mPhoneState=");
820        pw.println(mPhoneState);
821        pw.print("  mDataState=");
822        pw.println(mDataState);
823        pw.print("  mDataActivity=");
824        pw.println(mDataActivity);
825        pw.print("  mServiceState=");
826        pw.println(mServiceState.toString());
827        pw.print("  mNetworkName=");
828        pw.println(mNetworkName);
829        pw.print("  mNetworkNameDefault=");
830        pw.println(mNetworkNameDefault);
831        pw.print("  mNetworkNameSeparator=");
832        pw.println(mNetworkNameSeparator);
833        pw.print("  mPhoneSignalIconId=0x");
834        pw.print(Integer.toHexString(mPhoneSignalIconId));
835        pw.print("/");
836        pw.println(getResourceName(mPhoneSignalIconId));
837        pw.print("  mDataDirectionIconId=");
838        pw.print(Integer.toHexString(mDataDirectionIconId));
839        pw.print("/");
840        pw.println(getResourceName(mDataDirectionIconId));
841        pw.print("  mDataSignalIconId=");
842        pw.print(Integer.toHexString(mDataSignalIconId));
843        pw.print("/");
844        pw.println(getResourceName(mDataSignalIconId));
845        pw.print("  mDataTypeIconId=");
846        pw.print(Integer.toHexString(mDataTypeIconId));
847        pw.print("/");
848        pw.println(getResourceName(mDataTypeIconId));
849
850        pw.println("  - wifi ------");
851        pw.print("  mWifiEnabled=");
852        pw.println(mWifiEnabled);
853        pw.print("  mWifiConnected=");
854        pw.println(mWifiConnected);
855        pw.print("  mWifiLevel=");
856        pw.println(mWifiLevel);
857        pw.print("  mWifiSsid=");
858        pw.println(mWifiSsid);
859        pw.print("  mWifiIconId=");
860        pw.println(mWifiIconId);
861
862        pw.println("  - Bluetooth ----");
863        pw.print(" mBtReverseTethered=");
864        pw.println(mBluetoothTethered);
865
866        pw.println("  - connectivity ------");
867        pw.print("  mInetCondition=");
868        pw.println(mInetCondition);
869
870        pw.println("  - icons ------");
871        pw.print("  mLastPhoneSignalIconId=0x");
872        pw.print(Integer.toHexString(mLastPhoneSignalIconId));
873        pw.print("/");
874        pw.println(getResourceName(mLastPhoneSignalIconId));
875        pw.print("  mLastDataDirectionIconId=0x");
876        pw.print(Integer.toHexString(mLastDataDirectionIconId));
877        pw.print("/");
878        pw.println(getResourceName(mLastDataDirectionIconId));
879        pw.print("  mLastDataDirectionOverlayIconId=0x");
880        pw.print(Integer.toHexString(mLastDataDirectionOverlayIconId));
881        pw.print("/");
882        pw.println(getResourceName(mLastDataDirectionOverlayIconId));
883        pw.print("  mLastWifiIconId=0x");
884        pw.print(Integer.toHexString(mLastWifiIconId));
885        pw.print("/");
886        pw.println(getResourceName(mLastWifiIconId));
887        pw.print("  mLastCombinedSignalIconId=0x");
888        pw.print(Integer.toHexString(mLastCombinedSignalIconId));
889        pw.print("/");
890        pw.println(getResourceName(mLastCombinedSignalIconId));
891        pw.print("  mLastDataTypeIconId=0x");
892        pw.print(Integer.toHexString(mLastDataTypeIconId));
893        pw.print("/");
894        pw.println(getResourceName(mLastCombinedSignalIconId));
895        pw.print("  mLastLabel=");
896        pw.print(mLastLabel);
897    }
898
899    private String getResourceName(int resId) {
900        if (resId == 0) {
901            final Resources res = mContext.getResources();
902            try {
903                return res.getResourceName(resId);
904            } catch (android.content.res.Resources.NotFoundException ex) {
905                return "(unknown)";
906            }
907        } else {
908            return "(null)";
909        }
910    }
911
912}
913