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