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