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