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