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