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