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