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