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 android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.content.res.Resources;
24import android.net.ConnectivityManager;
25import android.net.NetworkInfo;
26import android.net.wifi.WifiConfiguration;
27import android.net.wifi.WifiInfo;
28import android.net.wifi.WifiManager;
29import android.net.wimax.WimaxManagerConstants;
30import android.os.Binder;
31import android.os.Handler;
32import android.os.Message;
33import android.os.Messenger;
34import android.os.RemoteException;
35import android.provider.Settings;
36import android.telephony.PhoneStateListener;
37import android.telephony.ServiceState;
38import android.telephony.SignalStrength;
39import android.telephony.TelephonyManager;
40import android.util.Slog;
41import android.view.View;
42import android.widget.ImageView;
43import android.widget.TextView;
44
45import com.android.internal.app.IBatteryStats;
46import com.android.internal.telephony.IccCardConstants;
47import com.android.internal.telephony.TelephonyIntents;
48import com.android.internal.telephony.cdma.EriInfo;
49import com.android.internal.util.AsyncChannel;
50import com.android.server.am.BatteryStatsService;
51import com.android.systemui.R;
52
53import java.io.FileDescriptor;
54import java.io.PrintWriter;
55import java.util.ArrayList;
56import java.util.List;
57
58public class NetworkController extends BroadcastReceiver {
59    // debug
60    static final String TAG = "StatusBar.NetworkController";
61    static final boolean DEBUG = false;
62    static final boolean CHATTY = false; // additional diagnostics, but not logspew
63
64    // telephony
65    boolean mHspaDataDistinguishable;
66    final TelephonyManager mPhone;
67    boolean mDataConnected;
68    IccCardConstants.State mSimState = IccCardConstants.State.READY;
69    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
70    int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
71    int mDataState = TelephonyManager.DATA_DISCONNECTED;
72    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
73    ServiceState mServiceState;
74    SignalStrength mSignalStrength;
75    int[] mDataIconList = TelephonyIcons.DATA_G[0];
76    String mNetworkName;
77    String mNetworkNameDefault;
78    String mNetworkNameSeparator;
79    int mPhoneSignalIconId;
80    int mQSPhoneSignalIconId;
81    int mDataDirectionIconId; // data + data direction on phones
82    int mDataSignalIconId;
83    int mDataTypeIconId;
84    int mQSDataTypeIconId;
85    int mAirplaneIconId;
86    boolean mDataActive;
87    int mMobileActivityIconId; // overlay arrows for data direction
88    int mLastSignalLevel;
89    boolean mShowPhoneRSSIForData = false;
90    boolean mShowAtLeastThreeGees = false;
91    boolean mAlwaysShowCdmaRssi = false;
92
93    String mContentDescriptionPhoneSignal;
94    String mContentDescriptionWifi;
95    String mContentDescriptionWimax;
96    String mContentDescriptionCombinedSignal;
97    String mContentDescriptionDataType;
98
99    // wifi
100    final WifiManager mWifiManager;
101    AsyncChannel mWifiChannel;
102    boolean mWifiEnabled, mWifiConnected;
103    int mWifiRssi, mWifiLevel;
104    String mWifiSsid;
105    int mWifiIconId = 0;
106    int mQSWifiIconId = 0;
107    int mWifiActivityIconId = 0; // overlay arrows for wifi direction
108    int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
109
110    // bluetooth
111    private boolean mBluetoothTethered = false;
112    private int mBluetoothTetherIconId =
113        com.android.internal.R.drawable.stat_sys_tether_bluetooth;
114
115    //wimax
116    private boolean mWimaxSupported = false;
117    private boolean mIsWimaxEnabled = false;
118    private boolean mWimaxConnected = false;
119    private boolean mWimaxIdle = false;
120    private int mWimaxIconId = 0;
121    private int mWimaxSignal = 0;
122    private int mWimaxState = 0;
123    private int mWimaxExtraState = 0;
124
125    // data connectivity (regardless of state, can we access the internet?)
126    // state of inet connection - 0 not connected, 100 connected
127    private boolean mConnected = false;
128    private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
129    private String mConnectedNetworkTypeName;
130    private int mInetCondition = 0;
131    private static final int INET_CONDITION_THRESHOLD = 50;
132
133    private boolean mAirplaneMode = false;
134    private boolean mLastAirplaneMode = true;
135
136    // our ui
137    Context mContext;
138    ArrayList<ImageView> mPhoneSignalIconViews = new ArrayList<ImageView>();
139    ArrayList<ImageView> mDataDirectionIconViews = new ArrayList<ImageView>();
140    ArrayList<ImageView> mDataDirectionOverlayIconViews = new ArrayList<ImageView>();
141    ArrayList<ImageView> mWifiIconViews = new ArrayList<ImageView>();
142    ArrayList<ImageView> mWimaxIconViews = new ArrayList<ImageView>();
143    ArrayList<ImageView> mCombinedSignalIconViews = new ArrayList<ImageView>();
144    ArrayList<ImageView> mDataTypeIconViews = new ArrayList<ImageView>();
145    ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
146    ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
147    ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
148    ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
149    ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
150    ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
151            new ArrayList<NetworkSignalChangedCallback>();
152    int mLastPhoneSignalIconId = -1;
153    int mLastDataDirectionIconId = -1;
154    int mLastDataDirectionOverlayIconId = -1;
155    int mLastWifiIconId = -1;
156    int mLastWimaxIconId = -1;
157    int mLastCombinedSignalIconId = -1;
158    int mLastDataTypeIconId = -1;
159    String mLastCombinedLabel = "";
160
161    private boolean mHasMobileDataFeature;
162
163    boolean mDataAndWifiStacked = false;
164
165    // yuck -- stop doing this here and put it in the framework
166    IBatteryStats mBatteryStats;
167
168    public interface SignalCluster {
169        void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon,
170                String contentDescription);
171        void setMobileDataIndicators(boolean visible, int strengthIcon, int activityIcon,
172                int typeIcon, String contentDescription, String typeContentDescription);
173        void setIsAirplaneMode(boolean is, int airplaneIcon);
174    }
175
176    public interface NetworkSignalChangedCallback {
177        void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
178                String wifitSignalContentDescriptionId, String description);
179        void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
180                String mobileSignalContentDescriptionId, int dataTypeIconId,
181                String dataTypeContentDescriptionId, String description);
182        void onAirplaneModeChanged(boolean enabled);
183    }
184
185    /**
186     * Construct this controller object and register for updates.
187     */
188    public NetworkController(Context context) {
189        mContext = context;
190        final Resources res = context.getResources();
191
192        ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
193                Context.CONNECTIVITY_SERVICE);
194        mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
195
196        mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
197        mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
198        mAlwaysShowCdmaRssi = res.getBoolean(
199                com.android.internal.R.bool.config_alwaysUseCdmaRssi);
200
201        // set up the default wifi icon, used when no radios have ever appeared
202        updateWifiIcons();
203        updateWimaxIcons();
204
205        // telephony
206        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
207        mPhone.listen(mPhoneStateListener,
208                          PhoneStateListener.LISTEN_SERVICE_STATE
209                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
210                        | PhoneStateListener.LISTEN_CALL_STATE
211                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
212                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
213        mHspaDataDistinguishable = mContext.getResources().getBoolean(
214                R.bool.config_hspa_data_distinguishable);
215        mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
216        mNetworkNameDefault = mContext.getString(
217                com.android.internal.R.string.lockscreen_carrier_default);
218        mNetworkName = mNetworkNameDefault;
219
220        // wifi
221        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
222        Handler handler = new WifiHandler();
223        mWifiChannel = new AsyncChannel();
224        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
225        if (wifiMessenger != null) {
226            mWifiChannel.connect(mContext, handler, wifiMessenger);
227        }
228
229        // broadcasts
230        IntentFilter filter = new IntentFilter();
231        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
232        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
233        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
234        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
235        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
236        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
237        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
238        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
239        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
240        mWimaxSupported = mContext.getResources().getBoolean(
241                com.android.internal.R.bool.config_wimaxEnabled);
242        if(mWimaxSupported) {
243            filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
244            filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
245            filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
246        }
247        context.registerReceiver(this, filter);
248
249        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
250        updateAirplaneMode();
251
252        // yuck
253        mBatteryStats = BatteryStatsService.getService();
254    }
255
256    public boolean hasMobileDataFeature() {
257        return mHasMobileDataFeature;
258    }
259
260    public boolean isEmergencyOnly() {
261        return (mServiceState != null && mServiceState.isEmergencyOnly());
262    }
263
264    public void addPhoneSignalIconView(ImageView v) {
265        mPhoneSignalIconViews.add(v);
266    }
267
268    public void addDataDirectionIconView(ImageView v) {
269        mDataDirectionIconViews.add(v);
270    }
271
272    public void addDataDirectionOverlayIconView(ImageView v) {
273        mDataDirectionOverlayIconViews.add(v);
274    }
275
276    public void addWifiIconView(ImageView v) {
277        mWifiIconViews.add(v);
278    }
279    public void addWimaxIconView(ImageView v) {
280        mWimaxIconViews.add(v);
281    }
282
283    public void addCombinedSignalIconView(ImageView v) {
284        mCombinedSignalIconViews.add(v);
285    }
286
287    public void addDataTypeIconView(ImageView v) {
288        mDataTypeIconViews.add(v);
289    }
290
291    public void addCombinedLabelView(TextView v) {
292        mCombinedLabelViews.add(v);
293    }
294
295    public void addMobileLabelView(TextView v) {
296        mMobileLabelViews.add(v);
297    }
298
299    public void addWifiLabelView(TextView v) {
300        mWifiLabelViews.add(v);
301    }
302
303    public void addEmergencyLabelView(TextView v) {
304        mEmergencyLabelViews.add(v);
305    }
306
307    public void addSignalCluster(SignalCluster cluster) {
308        mSignalClusters.add(cluster);
309        refreshSignalCluster(cluster);
310    }
311
312    public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
313        mSignalsChangedCallbacks.add(cb);
314        notifySignalsChangedCallbacks(cb);
315    }
316
317    public void refreshSignalCluster(SignalCluster cluster) {
318        cluster.setWifiIndicators(
319                // only show wifi in the cluster if connected or if wifi-only
320                mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
321                mWifiIconId,
322                mWifiActivityIconId,
323                mContentDescriptionWifi);
324
325        if (mIsWimaxEnabled && mWimaxConnected) {
326            // wimax is special
327            cluster.setMobileDataIndicators(
328                    true,
329                    mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
330                    mMobileActivityIconId,
331                    mDataTypeIconId,
332                    mContentDescriptionWimax,
333                    mContentDescriptionDataType);
334        } else {
335            // normal mobile data
336            cluster.setMobileDataIndicators(
337                    mHasMobileDataFeature,
338                    mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
339                    mMobileActivityIconId,
340                    mDataTypeIconId,
341                    mContentDescriptionPhoneSignal,
342                    mContentDescriptionDataType);
343        }
344        cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
345    }
346
347    void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
348        // only show wifi in the cluster if connected or if wifi-only
349        boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
350        String wifiDesc = wifiEnabled ?
351                mWifiSsid : null;
352        cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, mContentDescriptionWifi, wifiDesc);
353
354        if (isEmergencyOnly()) {
355            cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
356                    mContentDescriptionPhoneSignal, mQSDataTypeIconId, mContentDescriptionDataType,
357                    null);
358        } else {
359            if (mIsWimaxEnabled && mWimaxConnected) {
360                // Wimax is special
361                cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
362                        mContentDescriptionPhoneSignal, mQSDataTypeIconId,
363                        mContentDescriptionDataType, mNetworkName);
364            } else {
365                // Normal mobile data
366                cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
367                        mContentDescriptionPhoneSignal, mQSDataTypeIconId,
368                        mContentDescriptionDataType, mNetworkName);
369            }
370        }
371        cb.onAirplaneModeChanged(mAirplaneMode);
372    }
373
374    public void setStackedMode(boolean stacked) {
375        mDataAndWifiStacked = true;
376    }
377
378    @Override
379    public void onReceive(Context context, Intent intent) {
380        final String action = intent.getAction();
381        if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
382                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
383                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
384            updateWifiState(intent);
385            refreshViews();
386        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
387            updateSimState(intent);
388            updateDataIcon();
389            refreshViews();
390        } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
391            updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
392                        intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
393                        intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
394                        intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
395            refreshViews();
396        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
397                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
398            updateConnectivity(intent);
399            refreshViews();
400        } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
401            refreshViews();
402        } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
403            updateAirplaneMode();
404            refreshViews();
405        } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
406                action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
407                action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
408            updateWimaxState(intent);
409            refreshViews();
410        }
411    }
412
413
414    // ===== Telephony ==============================================================
415
416    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
417        @Override
418        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
419            if (DEBUG) {
420                Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
421                    ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
422            }
423            mSignalStrength = signalStrength;
424            updateTelephonySignalStrength();
425            refreshViews();
426        }
427
428        @Override
429        public void onServiceStateChanged(ServiceState state) {
430            if (DEBUG) {
431                Slog.d(TAG, "onServiceStateChanged state=" + state.getState());
432            }
433            mServiceState = state;
434            updateTelephonySignalStrength();
435            updateDataNetType();
436            updateDataIcon();
437            refreshViews();
438        }
439
440        @Override
441        public void onCallStateChanged(int state, String incomingNumber) {
442            if (DEBUG) {
443                Slog.d(TAG, "onCallStateChanged state=" + state);
444            }
445            // In cdma, if a voice call is made, RSSI should switch to 1x.
446            if (isCdma()) {
447                updateTelephonySignalStrength();
448                refreshViews();
449            }
450        }
451
452        @Override
453        public void onDataConnectionStateChanged(int state, int networkType) {
454            if (DEBUG) {
455                Slog.d(TAG, "onDataConnectionStateChanged: state=" + state
456                        + " type=" + networkType);
457            }
458            mDataState = state;
459            mDataNetType = networkType;
460            updateDataNetType();
461            updateDataIcon();
462            refreshViews();
463        }
464
465        @Override
466        public void onDataActivity(int direction) {
467            if (DEBUG) {
468                Slog.d(TAG, "onDataActivity: direction=" + direction);
469            }
470            mDataActivity = direction;
471            updateDataIcon();
472            refreshViews();
473        }
474    };
475
476    private final void updateSimState(Intent intent) {
477        String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
478        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
479            mSimState = IccCardConstants.State.ABSENT;
480        }
481        else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
482            mSimState = IccCardConstants.State.READY;
483        }
484        else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
485            final String lockedReason =
486                    intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
487            if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
488                mSimState = IccCardConstants.State.PIN_REQUIRED;
489            }
490            else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
491                mSimState = IccCardConstants.State.PUK_REQUIRED;
492            }
493            else {
494                mSimState = IccCardConstants.State.NETWORK_LOCKED;
495            }
496        } else {
497            mSimState = IccCardConstants.State.UNKNOWN;
498        }
499    }
500
501    private boolean isCdma() {
502        return (mSignalStrength != null) && !mSignalStrength.isGsm();
503    }
504
505    private boolean hasService() {
506        if (mServiceState != null) {
507            switch (mServiceState.getState()) {
508                case ServiceState.STATE_OUT_OF_SERVICE:
509                case ServiceState.STATE_POWER_OFF:
510                    return false;
511                default:
512                    return true;
513            }
514        } else {
515            return false;
516        }
517    }
518
519    private void updateAirplaneMode() {
520        mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
521            Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
522    }
523
524    private final void updateTelephonySignalStrength() {
525        if (!hasService()) {
526            if (CHATTY) Slog.d(TAG, "updateTelephonySignalStrength: !hasService()");
527            mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
528            mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
529            mDataSignalIconId = R.drawable.stat_sys_signal_null;
530        } else {
531            if (mSignalStrength == null) {
532                if (CHATTY) Slog.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
533                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
534                mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
535                mDataSignalIconId = R.drawable.stat_sys_signal_null;
536                mContentDescriptionPhoneSignal = mContext.getString(
537                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
538            } else {
539                int iconLevel;
540                int[] iconList;
541                if (isCdma() && mAlwaysShowCdmaRssi) {
542                    mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
543                    if(DEBUG) Slog.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
544                            + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
545                            + " instead of level=" + mSignalStrength.getLevel());
546                } else {
547                    mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
548                }
549
550                if (isCdma()) {
551                    if (isCdmaEri()) {
552                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
553                    } else {
554                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
555                    }
556                } else {
557                    // Though mPhone is a Manager, this call is not an IPC
558                    if (mPhone.isNetworkRoaming()) {
559                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
560                    } else {
561                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
562                    }
563                }
564                mPhoneSignalIconId = iconList[iconLevel];
565                mQSPhoneSignalIconId =
566                        TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel];
567                mContentDescriptionPhoneSignal = mContext.getString(
568                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
569                mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
570            }
571        }
572    }
573
574    private final void updateDataNetType() {
575        if (mIsWimaxEnabled && mWimaxConnected) {
576            // wimax is a special 4g network not handled by telephony
577            mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
578            mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
579            mQSDataTypeIconId = R.drawable.ic_qs_signal_4g;
580            mContentDescriptionDataType = mContext.getString(
581                    R.string.accessibility_data_connection_4g);
582        } else {
583            switch (mDataNetType) {
584                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
585                    if (!mShowAtLeastThreeGees) {
586                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
587                        mDataTypeIconId = 0;
588                        mQSDataTypeIconId = 0;
589                        mContentDescriptionDataType = mContext.getString(
590                                R.string.accessibility_data_connection_gprs);
591                        break;
592                    } else {
593                        // fall through
594                    }
595                case TelephonyManager.NETWORK_TYPE_EDGE:
596                    if (!mShowAtLeastThreeGees) {
597                        mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
598                        mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
599                        mQSDataTypeIconId = R.drawable.ic_qs_signal_e;
600                        mContentDescriptionDataType = mContext.getString(
601                                R.string.accessibility_data_connection_edge);
602                        break;
603                    } else {
604                        // fall through
605                    }
606                case TelephonyManager.NETWORK_TYPE_UMTS:
607                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
608                    mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
609                    mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
610                    mContentDescriptionDataType = mContext.getString(
611                            R.string.accessibility_data_connection_3g);
612                    break;
613                case TelephonyManager.NETWORK_TYPE_HSDPA:
614                case TelephonyManager.NETWORK_TYPE_HSUPA:
615                case TelephonyManager.NETWORK_TYPE_HSPA:
616                case TelephonyManager.NETWORK_TYPE_HSPAP:
617                    if (mHspaDataDistinguishable) {
618                        mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
619                        mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
620                        mQSDataTypeIconId = R.drawable.ic_qs_signal_h;
621                        mContentDescriptionDataType = mContext.getString(
622                                R.string.accessibility_data_connection_3_5g);
623                    } else {
624                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
625                        mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
626                        mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
627                        mContentDescriptionDataType = mContext.getString(
628                                R.string.accessibility_data_connection_3g);
629                    }
630                    break;
631                case TelephonyManager.NETWORK_TYPE_CDMA:
632                    if (!mShowAtLeastThreeGees) {
633                        // display 1xRTT for IS95A/B
634                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
635                        mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
636                        mQSDataTypeIconId = R.drawable.ic_qs_signal_1x;
637                        mContentDescriptionDataType = mContext.getString(
638                                R.string.accessibility_data_connection_cdma);
639                        break;
640                    } else {
641                        // fall through
642                    }
643                case TelephonyManager.NETWORK_TYPE_1xRTT:
644                    if (!mShowAtLeastThreeGees) {
645                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
646                        mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
647                        mQSDataTypeIconId = R.drawable.ic_qs_signal_1x;
648                        mContentDescriptionDataType = mContext.getString(
649                                R.string.accessibility_data_connection_cdma);
650                        break;
651                    } else {
652                        // fall through
653                    }
654                case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
655                case TelephonyManager.NETWORK_TYPE_EVDO_A:
656                case TelephonyManager.NETWORK_TYPE_EVDO_B:
657                case TelephonyManager.NETWORK_TYPE_EHRPD:
658                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
659                    mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
660                    mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
661                    mContentDescriptionDataType = mContext.getString(
662                            R.string.accessibility_data_connection_3g);
663                    break;
664                case TelephonyManager.NETWORK_TYPE_LTE:
665                    mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
666                    mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
667                    mQSDataTypeIconId = R.drawable.ic_qs_signal_4g;
668                    mContentDescriptionDataType = mContext.getString(
669                            R.string.accessibility_data_connection_4g);
670                    break;
671                default:
672                    if (!mShowAtLeastThreeGees) {
673                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
674                        mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
675                        mQSDataTypeIconId = R.drawable.ic_qs_signal_g;
676                        mContentDescriptionDataType = mContext.getString(
677                                R.string.accessibility_data_connection_gprs);
678                    } else {
679                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
680                        mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
681                        mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
682                        mContentDescriptionDataType = mContext.getString(
683                                R.string.accessibility_data_connection_3g);
684                    }
685                    break;
686            }
687        }
688
689        if (isCdma()) {
690            if (isCdmaEri()) {
691                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
692                mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
693            }
694        } else if (mPhone.isNetworkRoaming()) {
695                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
696                mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
697        }
698    }
699
700    boolean isCdmaEri() {
701        if (mServiceState != null) {
702            final int iconIndex = mServiceState.getCdmaEriIconIndex();
703            if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
704                final int iconMode = mServiceState.getCdmaEriIconMode();
705                if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
706                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
707                    return true;
708                }
709            }
710        }
711        return false;
712    }
713
714    private final void updateDataIcon() {
715        int iconId;
716        boolean visible = true;
717
718        if (!isCdma()) {
719            // GSM case, we have to check also the sim state
720            if (mSimState == IccCardConstants.State.READY ||
721                    mSimState == IccCardConstants.State.UNKNOWN) {
722                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
723                    switch (mDataActivity) {
724                        case TelephonyManager.DATA_ACTIVITY_IN:
725                            iconId = mDataIconList[1];
726                            break;
727                        case TelephonyManager.DATA_ACTIVITY_OUT:
728                            iconId = mDataIconList[2];
729                            break;
730                        case TelephonyManager.DATA_ACTIVITY_INOUT:
731                            iconId = mDataIconList[3];
732                            break;
733                        default:
734                            iconId = mDataIconList[0];
735                            break;
736                    }
737                    mDataDirectionIconId = iconId;
738                } else {
739                    iconId = 0;
740                    visible = false;
741                }
742            } else {
743                iconId = R.drawable.stat_sys_no_sim;
744                visible = false; // no SIM? no data
745            }
746        } else {
747            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
748            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
749                switch (mDataActivity) {
750                    case TelephonyManager.DATA_ACTIVITY_IN:
751                        iconId = mDataIconList[1];
752                        break;
753                    case TelephonyManager.DATA_ACTIVITY_OUT:
754                        iconId = mDataIconList[2];
755                        break;
756                    case TelephonyManager.DATA_ACTIVITY_INOUT:
757                        iconId = mDataIconList[3];
758                        break;
759                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
760                    default:
761                        iconId = mDataIconList[0];
762                        break;
763                }
764            } else {
765                iconId = 0;
766                visible = false;
767            }
768        }
769
770        // yuck - this should NOT be done by the status bar
771        long ident = Binder.clearCallingIdentity();
772        try {
773            mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
774        } catch (RemoteException e) {
775        } finally {
776            Binder.restoreCallingIdentity(ident);
777        }
778
779        mDataDirectionIconId = iconId;
780        mDataConnected = visible;
781    }
782
783    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
784        if (false) {
785            Slog.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
786                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
787        }
788        StringBuilder str = new StringBuilder();
789        boolean something = false;
790        if (showPlmn && plmn != null) {
791            str.append(plmn);
792            something = true;
793        }
794        if (showSpn && spn != null) {
795            if (something) {
796                str.append(mNetworkNameSeparator);
797            }
798            str.append(spn);
799            something = true;
800        }
801        if (something) {
802            mNetworkName = str.toString();
803        } else {
804            mNetworkName = mNetworkNameDefault;
805        }
806    }
807
808    // ===== Wifi ===================================================================
809
810    class WifiHandler extends Handler {
811        @Override
812        public void handleMessage(Message msg) {
813            switch (msg.what) {
814                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
815                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
816                        mWifiChannel.sendMessage(Message.obtain(this,
817                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
818                    } else {
819                        Slog.e(TAG, "Failed to connect to wifi");
820                    }
821                    break;
822                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
823                    if (msg.arg1 != mWifiActivity) {
824                        mWifiActivity = msg.arg1;
825                        refreshViews();
826                    }
827                    break;
828                default:
829                    //Ignore
830                    break;
831            }
832        }
833    }
834
835    private void updateWifiState(Intent intent) {
836        final String action = intent.getAction();
837        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
838            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
839                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
840
841        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
842            final NetworkInfo networkInfo = (NetworkInfo)
843                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
844            boolean wasConnected = mWifiConnected;
845            mWifiConnected = networkInfo != null && networkInfo.isConnected();
846            // If we just connected, grab the inintial signal strength and ssid
847            if (mWifiConnected && !wasConnected) {
848                // try getting it out of the intent first
849                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
850                if (info == null) {
851                    info = mWifiManager.getConnectionInfo();
852                }
853                if (info != null) {
854                    mWifiSsid = huntForSsid(info);
855                } else {
856                    mWifiSsid = null;
857                }
858            } else if (!mWifiConnected) {
859                mWifiSsid = null;
860            }
861        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
862            mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
863            mWifiLevel = WifiManager.calculateSignalLevel(
864                    mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
865        }
866
867        updateWifiIcons();
868    }
869
870    private void updateWifiIcons() {
871        if (mWifiConnected) {
872            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
873            mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
874            mContentDescriptionWifi = mContext.getString(
875                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
876        } else {
877            if (mDataAndWifiStacked) {
878                mWifiIconId = 0;
879                mQSWifiIconId = 0;
880            } else {
881                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
882                mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
883            }
884            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
885        }
886    }
887
888    private String huntForSsid(WifiInfo info) {
889        String ssid = info.getSSID();
890        if (ssid != null) {
891            return ssid;
892        }
893        // OK, it's not in the connectionInfo; we have to go hunting for it
894        List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
895        for (WifiConfiguration net : networks) {
896            if (net.networkId == info.getNetworkId()) {
897                return net.SSID;
898            }
899        }
900        return null;
901    }
902
903
904    // ===== Wimax ===================================================================
905    private final void updateWimaxState(Intent intent) {
906        final String action = intent.getAction();
907        boolean wasConnected = mWimaxConnected;
908        if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) {
909            int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
910                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
911            mIsWimaxEnabled = (wimaxStatus ==
912                    WimaxManagerConstants.NET_4G_STATE_ENABLED);
913        } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
914            mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
915        } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
916            mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
917                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
918            mWimaxExtraState = intent.getIntExtra(
919                    WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
920                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
921            mWimaxConnected = (mWimaxState ==
922                    WimaxManagerConstants.WIMAX_STATE_CONNECTED);
923            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
924        }
925        updateDataNetType();
926        updateWimaxIcons();
927    }
928
929    private void updateWimaxIcons() {
930        if (mIsWimaxEnabled) {
931            if (mWimaxConnected) {
932                if (mWimaxIdle)
933                    mWimaxIconId = WimaxIcons.WIMAX_IDLE;
934                else
935                    mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
936                mContentDescriptionWimax = mContext.getString(
937                        AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
938            } else {
939                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
940                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
941            }
942        } else {
943            mWimaxIconId = 0;
944        }
945    }
946
947    // ===== Full or limited Internet connectivity ==================================
948
949    private void updateConnectivity(Intent intent) {
950        if (CHATTY) {
951            Slog.d(TAG, "updateConnectivity: intent=" + intent);
952        }
953
954        final ConnectivityManager connManager = (ConnectivityManager) mContext
955                .getSystemService(Context.CONNECTIVITY_SERVICE);
956        final NetworkInfo info = connManager.getActiveNetworkInfo();
957
958        // Are we connected at all, by any interface?
959        mConnected = info != null && info.isConnected();
960        if (mConnected) {
961            mConnectedNetworkType = info.getType();
962            mConnectedNetworkTypeName = info.getTypeName();
963        } else {
964            mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
965            mConnectedNetworkTypeName = null;
966        }
967
968        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
969
970        if (CHATTY) {
971            Slog.d(TAG, "updateConnectivity: networkInfo=" + info);
972            Slog.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
973        }
974
975        mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
976
977        if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
978            mBluetoothTethered = info.isConnected();
979        } else {
980            mBluetoothTethered = false;
981        }
982
983        // We want to update all the icons, all at once, for any condition change
984        updateDataNetType();
985        updateWimaxIcons();
986        updateDataIcon();
987        updateTelephonySignalStrength();
988        updateWifiIcons();
989    }
990
991
992    // ===== Update the views =======================================================
993
994    void refreshViews() {
995        Context context = mContext;
996
997        int combinedSignalIconId = 0;
998        int combinedActivityIconId = 0;
999        String combinedLabel = "";
1000        String wifiLabel = "";
1001        String mobileLabel = "";
1002        int N;
1003        final boolean emergencyOnly = isEmergencyOnly();
1004
1005        if (!mHasMobileDataFeature) {
1006            mDataSignalIconId = mPhoneSignalIconId = 0;
1007            mQSPhoneSignalIconId = 0;
1008            mobileLabel = "";
1009        } else {
1010            // We want to show the carrier name if in service and either:
1011            //   - We are connected to mobile data, or
1012            //   - We are not connected to mobile data, as long as the *reason* packets are not
1013            //     being routed over that link is that we have better connectivity via wifi.
1014            // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
1015            // is connected, we show nothing.
1016            // Otherwise (nothing connected) we show "No internet connection".
1017
1018            if (mDataConnected) {
1019                mobileLabel = mNetworkName;
1020            } else if (mConnected || emergencyOnly) {
1021                if (hasService() || emergencyOnly) {
1022                    // The isEmergencyOnly test covers the case of a phone with no SIM
1023                    mobileLabel = mNetworkName;
1024                } else {
1025                    // Tablets, basically
1026                    mobileLabel = "";
1027                }
1028            } else {
1029                mobileLabel
1030                    = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1031            }
1032
1033            // Now for things that should only be shown when actually using mobile data.
1034            if (mDataConnected) {
1035                combinedSignalIconId = mDataSignalIconId;
1036                switch (mDataActivity) {
1037                    case TelephonyManager.DATA_ACTIVITY_IN:
1038                        mMobileActivityIconId = R.drawable.stat_sys_signal_in;
1039                        break;
1040                    case TelephonyManager.DATA_ACTIVITY_OUT:
1041                        mMobileActivityIconId = R.drawable.stat_sys_signal_out;
1042                        break;
1043                    case TelephonyManager.DATA_ACTIVITY_INOUT:
1044                        mMobileActivityIconId = R.drawable.stat_sys_signal_inout;
1045                        break;
1046                    default:
1047                        mMobileActivityIconId = 0;
1048                        break;
1049                }
1050
1051                combinedLabel = mobileLabel;
1052                combinedActivityIconId = mMobileActivityIconId;
1053                combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
1054                mContentDescriptionCombinedSignal = mContentDescriptionDataType;
1055            } else {
1056                mMobileActivityIconId = 0;
1057            }
1058        }
1059
1060        if (mWifiConnected) {
1061            if (mWifiSsid == null) {
1062                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
1063                mWifiActivityIconId = 0; // no wifis, no bits
1064            } else {
1065                wifiLabel = mWifiSsid;
1066                if (DEBUG) {
1067                    wifiLabel += "xxxxXXXXxxxxXXXX";
1068                }
1069                switch (mWifiActivity) {
1070                    case WifiManager.DATA_ACTIVITY_IN:
1071                        mWifiActivityIconId = R.drawable.stat_sys_wifi_in;
1072                        break;
1073                    case WifiManager.DATA_ACTIVITY_OUT:
1074                        mWifiActivityIconId = R.drawable.stat_sys_wifi_out;
1075                        break;
1076                    case WifiManager.DATA_ACTIVITY_INOUT:
1077                        mWifiActivityIconId = R.drawable.stat_sys_wifi_inout;
1078                        break;
1079                    case WifiManager.DATA_ACTIVITY_NONE:
1080                        mWifiActivityIconId = 0;
1081                        break;
1082                }
1083            }
1084
1085            combinedActivityIconId = mWifiActivityIconId;
1086            combinedLabel = wifiLabel;
1087            combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
1088            mContentDescriptionCombinedSignal = mContentDescriptionWifi;
1089        } else {
1090            if (mHasMobileDataFeature) {
1091                wifiLabel = "";
1092            } else {
1093                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1094            }
1095        }
1096
1097        if (mBluetoothTethered) {
1098            combinedLabel = mContext.getString(R.string.bluetooth_tethered);
1099            combinedSignalIconId = mBluetoothTetherIconId;
1100            mContentDescriptionCombinedSignal = mContext.getString(
1101                    R.string.accessibility_bluetooth_tether);
1102        }
1103
1104        final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
1105        if (ethernetConnected) {
1106            combinedLabel = context.getString(R.string.ethernet_label);
1107        }
1108
1109        if (mAirplaneMode &&
1110                (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
1111            // Only display the flight-mode icon if not in "emergency calls only" mode.
1112
1113            // look again; your radios are now airplanes
1114            mContentDescriptionPhoneSignal = mContext.getString(
1115                    R.string.accessibility_airplane_mode);
1116            mAirplaneIconId = R.drawable.stat_sys_signal_flightmode;
1117            mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
1118            mQSPhoneSignalIconId = 0;
1119
1120            // combined values from connected wifi take precedence over airplane mode
1121            if (mWifiConnected) {
1122                // Suppress "No internet connection." from mobile if wifi connected.
1123                mobileLabel = "";
1124            } else {
1125                if (mHasMobileDataFeature) {
1126                    // let the mobile icon show "No internet connection."
1127                    wifiLabel = "";
1128                } else {
1129                    wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1130                    combinedLabel = wifiLabel;
1131                }
1132                mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
1133                combinedSignalIconId = mDataSignalIconId;
1134            }
1135        }
1136        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
1137            // pretty much totally disconnected
1138
1139            combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1140            // On devices without mobile radios, we want to show the wifi icon
1141            combinedSignalIconId =
1142                mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
1143            mContentDescriptionCombinedSignal = mHasMobileDataFeature
1144                ? mContentDescriptionDataType : mContentDescriptionWifi;
1145
1146            mDataTypeIconId = 0;
1147            mQSDataTypeIconId = 0;
1148            if (isCdma()) {
1149                if (isCdmaEri()) {
1150                    mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
1151                    mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
1152                }
1153            } else if (mPhone.isNetworkRoaming()) {
1154                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
1155                mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
1156            }
1157        }
1158
1159        if (DEBUG) {
1160            Slog.d(TAG, "refreshViews connected={"
1161                    + (mWifiConnected?" wifi":"")
1162                    + (mDataConnected?" data":"")
1163                    + " } level="
1164                    + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
1165                    + " combinedSignalIconId=0x"
1166                    + Integer.toHexString(combinedSignalIconId)
1167                    + "/" + getResourceName(combinedSignalIconId)
1168                    + " combinedActivityIconId=0x" + Integer.toHexString(combinedActivityIconId)
1169                    + " mobileLabel=" + mobileLabel
1170                    + " wifiLabel=" + wifiLabel
1171                    + " emergencyOnly=" + emergencyOnly
1172                    + " combinedLabel=" + combinedLabel
1173                    + " mAirplaneMode=" + mAirplaneMode
1174                    + " mDataActivity=" + mDataActivity
1175                    + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
1176                    + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId)
1177                    + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
1178                    + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
1179                    + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
1180                    + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId)
1181                    + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
1182                    + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId)
1183                    + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
1184        }
1185
1186        if (mLastPhoneSignalIconId          != mPhoneSignalIconId
1187         || mLastDataDirectionOverlayIconId != combinedActivityIconId
1188         || mLastWifiIconId                 != mWifiIconId
1189         || mLastWimaxIconId                != mWimaxIconId
1190         || mLastDataTypeIconId             != mDataTypeIconId
1191         || mLastAirplaneMode               != mAirplaneMode)
1192        {
1193            // NB: the mLast*s will be updated later
1194            for (SignalCluster cluster : mSignalClusters) {
1195                refreshSignalCluster(cluster);
1196            }
1197            for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
1198                notifySignalsChangedCallbacks(cb);
1199            }
1200        }
1201
1202        if (mLastAirplaneMode != mAirplaneMode) {
1203            mLastAirplaneMode = mAirplaneMode;
1204        }
1205
1206        // the phone icon on phones
1207        if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
1208            mLastPhoneSignalIconId = mPhoneSignalIconId;
1209            N = mPhoneSignalIconViews.size();
1210            for (int i=0; i<N; i++) {
1211                final ImageView v = mPhoneSignalIconViews.get(i);
1212                if (mPhoneSignalIconId == 0) {
1213                    v.setVisibility(View.GONE);
1214                } else {
1215                    v.setVisibility(View.VISIBLE);
1216                    v.setImageResource(mPhoneSignalIconId);
1217                    v.setContentDescription(mContentDescriptionPhoneSignal);
1218                }
1219            }
1220        }
1221
1222        // the data icon on phones
1223        if (mLastDataDirectionIconId != mDataDirectionIconId) {
1224            mLastDataDirectionIconId = mDataDirectionIconId;
1225            N = mDataDirectionIconViews.size();
1226            for (int i=0; i<N; i++) {
1227                final ImageView v = mDataDirectionIconViews.get(i);
1228                v.setImageResource(mDataDirectionIconId);
1229                v.setContentDescription(mContentDescriptionDataType);
1230            }
1231        }
1232
1233        // the wifi icon on phones
1234        if (mLastWifiIconId != mWifiIconId) {
1235            mLastWifiIconId = mWifiIconId;
1236            N = mWifiIconViews.size();
1237            for (int i=0; i<N; i++) {
1238                final ImageView v = mWifiIconViews.get(i);
1239                if (mWifiIconId == 0) {
1240                    v.setVisibility(View.GONE);
1241                } else {
1242                    v.setVisibility(View.VISIBLE);
1243                    v.setImageResource(mWifiIconId);
1244                    v.setContentDescription(mContentDescriptionWifi);
1245                }
1246            }
1247        }
1248
1249        // the wimax icon on phones
1250        if (mLastWimaxIconId != mWimaxIconId) {
1251            mLastWimaxIconId = mWimaxIconId;
1252            N = mWimaxIconViews.size();
1253            for (int i=0; i<N; i++) {
1254                final ImageView v = mWimaxIconViews.get(i);
1255                if (mWimaxIconId == 0) {
1256                    v.setVisibility(View.GONE);
1257                } else {
1258                    v.setVisibility(View.VISIBLE);
1259                    v.setImageResource(mWimaxIconId);
1260                    v.setContentDescription(mContentDescriptionWimax);
1261                }
1262           }
1263        }
1264        // the combined data signal icon
1265        if (mLastCombinedSignalIconId != combinedSignalIconId) {
1266            mLastCombinedSignalIconId = combinedSignalIconId;
1267            N = mCombinedSignalIconViews.size();
1268            for (int i=0; i<N; i++) {
1269                final ImageView v = mCombinedSignalIconViews.get(i);
1270                v.setImageResource(combinedSignalIconId);
1271                v.setContentDescription(mContentDescriptionCombinedSignal);
1272            }
1273        }
1274
1275        // the data network type overlay
1276        if (mLastDataTypeIconId != mDataTypeIconId) {
1277            mLastDataTypeIconId = mDataTypeIconId;
1278            N = mDataTypeIconViews.size();
1279            for (int i=0; i<N; i++) {
1280                final ImageView v = mDataTypeIconViews.get(i);
1281                if (mDataTypeIconId == 0) {
1282                    v.setVisibility(View.GONE);
1283                } else {
1284                    v.setVisibility(View.VISIBLE);
1285                    v.setImageResource(mDataTypeIconId);
1286                    v.setContentDescription(mContentDescriptionDataType);
1287                }
1288            }
1289        }
1290
1291        // the data direction overlay
1292        if (mLastDataDirectionOverlayIconId != combinedActivityIconId) {
1293            if (DEBUG) {
1294                Slog.d(TAG, "changing data overlay icon id to " + combinedActivityIconId);
1295            }
1296            mLastDataDirectionOverlayIconId = combinedActivityIconId;
1297            N = mDataDirectionOverlayIconViews.size();
1298            for (int i=0; i<N; i++) {
1299                final ImageView v = mDataDirectionOverlayIconViews.get(i);
1300                if (combinedActivityIconId == 0) {
1301                    v.setVisibility(View.GONE);
1302                } else {
1303                    v.setVisibility(View.VISIBLE);
1304                    v.setImageResource(combinedActivityIconId);
1305                    v.setContentDescription(mContentDescriptionDataType);
1306                }
1307            }
1308        }
1309
1310        // the combinedLabel in the notification panel
1311        if (!mLastCombinedLabel.equals(combinedLabel)) {
1312            mLastCombinedLabel = combinedLabel;
1313            N = mCombinedLabelViews.size();
1314            for (int i=0; i<N; i++) {
1315                TextView v = mCombinedLabelViews.get(i);
1316                v.setText(combinedLabel);
1317            }
1318        }
1319
1320        // wifi label
1321        N = mWifiLabelViews.size();
1322        for (int i=0; i<N; i++) {
1323            TextView v = mWifiLabelViews.get(i);
1324            v.setText(wifiLabel);
1325            if ("".equals(wifiLabel)) {
1326                v.setVisibility(View.GONE);
1327            } else {
1328                v.setVisibility(View.VISIBLE);
1329            }
1330        }
1331
1332        // mobile label
1333        N = mMobileLabelViews.size();
1334        for (int i=0; i<N; i++) {
1335            TextView v = mMobileLabelViews.get(i);
1336            v.setText(mobileLabel);
1337            if ("".equals(mobileLabel)) {
1338                v.setVisibility(View.GONE);
1339            } else {
1340                v.setVisibility(View.VISIBLE);
1341            }
1342        }
1343
1344        // e-call label
1345        N = mEmergencyLabelViews.size();
1346        for (int i=0; i<N; i++) {
1347            TextView v = mEmergencyLabelViews.get(i);
1348            if (!emergencyOnly) {
1349                v.setVisibility(View.GONE);
1350            } else {
1351                v.setText(mobileLabel); // comes from the telephony stack
1352                v.setVisibility(View.VISIBLE);
1353            }
1354        }
1355    }
1356
1357    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1358        pw.println("NetworkController state:");
1359        pw.println(String.format("  %s network type %d (%s)",
1360                mConnected?"CONNECTED":"DISCONNECTED",
1361                mConnectedNetworkType, mConnectedNetworkTypeName));
1362        pw.println("  - telephony ------");
1363        pw.print("  hasService()=");
1364        pw.println(hasService());
1365        pw.print("  mHspaDataDistinguishable=");
1366        pw.println(mHspaDataDistinguishable);
1367        pw.print("  mDataConnected=");
1368        pw.println(mDataConnected);
1369        pw.print("  mSimState=");
1370        pw.println(mSimState);
1371        pw.print("  mPhoneState=");
1372        pw.println(mPhoneState);
1373        pw.print("  mDataState=");
1374        pw.println(mDataState);
1375        pw.print("  mDataActivity=");
1376        pw.println(mDataActivity);
1377        pw.print("  mDataNetType=");
1378        pw.print(mDataNetType);
1379        pw.print("/");
1380        pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
1381        pw.print("  mServiceState=");
1382        pw.println(mServiceState);
1383        pw.print("  mSignalStrength=");
1384        pw.println(mSignalStrength);
1385        pw.print("  mLastSignalLevel=");
1386        pw.println(mLastSignalLevel);
1387        pw.print("  mNetworkName=");
1388        pw.println(mNetworkName);
1389        pw.print("  mNetworkNameDefault=");
1390        pw.println(mNetworkNameDefault);
1391        pw.print("  mNetworkNameSeparator=");
1392        pw.println(mNetworkNameSeparator.replace("\n","\\n"));
1393        pw.print("  mPhoneSignalIconId=0x");
1394        pw.print(Integer.toHexString(mPhoneSignalIconId));
1395        pw.print("/");
1396        pw.print("  mQSPhoneSignalIconId=0x");
1397        pw.print(Integer.toHexString(mQSPhoneSignalIconId));
1398        pw.print("/");
1399        pw.println(getResourceName(mPhoneSignalIconId));
1400        pw.print("  mDataDirectionIconId=");
1401        pw.print(Integer.toHexString(mDataDirectionIconId));
1402        pw.print("/");
1403        pw.println(getResourceName(mDataDirectionIconId));
1404        pw.print("  mDataSignalIconId=");
1405        pw.print(Integer.toHexString(mDataSignalIconId));
1406        pw.print("/");
1407        pw.println(getResourceName(mDataSignalIconId));
1408        pw.print("  mDataTypeIconId=");
1409        pw.print(Integer.toHexString(mDataTypeIconId));
1410        pw.print("/");
1411        pw.println(getResourceName(mDataTypeIconId));
1412        pw.print("  mQSDataTypeIconId=");
1413        pw.print(Integer.toHexString(mQSDataTypeIconId));
1414        pw.print("/");
1415        pw.println(getResourceName(mQSDataTypeIconId));
1416
1417        pw.println("  - wifi ------");
1418        pw.print("  mWifiEnabled=");
1419        pw.println(mWifiEnabled);
1420        pw.print("  mWifiConnected=");
1421        pw.println(mWifiConnected);
1422        pw.print("  mWifiRssi=");
1423        pw.println(mWifiRssi);
1424        pw.print("  mWifiLevel=");
1425        pw.println(mWifiLevel);
1426        pw.print("  mWifiSsid=");
1427        pw.println(mWifiSsid);
1428        pw.println(String.format("  mWifiIconId=0x%08x/%s",
1429                    mWifiIconId, getResourceName(mWifiIconId)));
1430        pw.println(String.format("  mQSWifiIconId=0x%08x/%s",
1431                    mQSWifiIconId, getResourceName(mQSWifiIconId)));
1432        pw.print("  mWifiActivity=");
1433        pw.println(mWifiActivity);
1434
1435        if (mWimaxSupported) {
1436            pw.println("  - wimax ------");
1437            pw.print("  mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
1438            pw.print("  mWimaxConnected="); pw.println(mWimaxConnected);
1439            pw.print("  mWimaxIdle="); pw.println(mWimaxIdle);
1440            pw.println(String.format("  mWimaxIconId=0x%08x/%s",
1441                        mWimaxIconId, getResourceName(mWimaxIconId)));
1442            pw.println(String.format("  mWimaxSignal=%d", mWimaxSignal));
1443            pw.println(String.format("  mWimaxState=%d", mWimaxState));
1444            pw.println(String.format("  mWimaxExtraState=%d", mWimaxExtraState));
1445        }
1446
1447        pw.println("  - Bluetooth ----");
1448        pw.print("  mBtReverseTethered=");
1449        pw.println(mBluetoothTethered);
1450
1451        pw.println("  - connectivity ------");
1452        pw.print("  mInetCondition=");
1453        pw.println(mInetCondition);
1454
1455        pw.println("  - icons ------");
1456        pw.print("  mLastPhoneSignalIconId=0x");
1457        pw.print(Integer.toHexString(mLastPhoneSignalIconId));
1458        pw.print("/");
1459        pw.println(getResourceName(mLastPhoneSignalIconId));
1460        pw.print("  mLastDataDirectionIconId=0x");
1461        pw.print(Integer.toHexString(mLastDataDirectionIconId));
1462        pw.print("/");
1463        pw.println(getResourceName(mLastDataDirectionIconId));
1464        pw.print("  mLastDataDirectionOverlayIconId=0x");
1465        pw.print(Integer.toHexString(mLastDataDirectionOverlayIconId));
1466        pw.print("/");
1467        pw.println(getResourceName(mLastDataDirectionOverlayIconId));
1468        pw.print("  mLastWifiIconId=0x");
1469        pw.print(Integer.toHexString(mLastWifiIconId));
1470        pw.print("/");
1471        pw.println(getResourceName(mLastWifiIconId));
1472        pw.print("  mLastCombinedSignalIconId=0x");
1473        pw.print(Integer.toHexString(mLastCombinedSignalIconId));
1474        pw.print("/");
1475        pw.println(getResourceName(mLastCombinedSignalIconId));
1476        pw.print("  mLastDataTypeIconId=0x");
1477        pw.print(Integer.toHexString(mLastDataTypeIconId));
1478        pw.print("/");
1479        pw.println(getResourceName(mLastDataTypeIconId));
1480        pw.print("  mLastCombinedLabel=");
1481        pw.print(mLastCombinedLabel);
1482        pw.println("");
1483    }
1484
1485    private String getResourceName(int resId) {
1486        if (resId != 0) {
1487            final Resources res = mContext.getResources();
1488            try {
1489                return res.getResourceName(resId);
1490            } catch (android.content.res.Resources.NotFoundException ex) {
1491                return "(unknown)";
1492            }
1493        } else {
1494            return "(null)";
1495        }
1496    }
1497
1498}
1499