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