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