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