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            mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
518            mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
519            mDataSignalIconId = R.drawable.stat_sys_signal_null;
520        } else {
521            if (mSignalStrength == null) {
522                if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
523                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
524                mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
525                mDataSignalIconId = R.drawable.stat_sys_signal_null;
526                mContentDescriptionPhoneSignal = mContext.getString(
527                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
528            } else {
529                int iconLevel;
530                int[] iconList;
531                if (isCdma() && mAlwaysShowCdmaRssi) {
532                    mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
533                    if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
534                            + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
535                            + " instead of level=" + mSignalStrength.getLevel());
536                } else {
537                    mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
538                }
539
540                if (isCdma()) {
541                    if (isCdmaEri()) {
542                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
543                    } else {
544                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
545                    }
546                } else {
547                    // Though mPhone is a Manager, this call is not an IPC
548                    if (mPhone.isNetworkRoaming()) {
549                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
550                    } else {
551                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
552                    }
553                }
554                mPhoneSignalIconId = iconList[iconLevel];
555                mQSPhoneSignalIconId =
556                        TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel];
557                mContentDescriptionPhoneSignal = mContext.getString(
558                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
559                mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
560            }
561        }
562    }
563
564    private final void updateDataNetType() {
565        if (mIsWimaxEnabled && mWimaxConnected) {
566            // wimax is a special 4g network not handled by telephony
567            mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
568            mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
569            mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
570            mContentDescriptionDataType = mContext.getString(
571                    R.string.accessibility_data_connection_4g);
572        } else {
573            switch (mDataNetType) {
574                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
575                    if (!mShowAtLeastThreeGees) {
576                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
577                        mDataTypeIconId = 0;
578                        mQSDataTypeIconId = 0;
579                        mContentDescriptionDataType = mContext.getString(
580                                R.string.accessibility_data_connection_gprs);
581                        break;
582                    } else {
583                        // fall through
584                    }
585                case TelephonyManager.NETWORK_TYPE_EDGE:
586                    if (!mShowAtLeastThreeGees) {
587                        mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
588                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e;
589                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition];
590                        mContentDescriptionDataType = mContext.getString(
591                                R.string.accessibility_data_connection_edge);
592                        break;
593                    } else {
594                        // fall through
595                    }
596                case TelephonyManager.NETWORK_TYPE_UMTS:
597                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
598                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
599                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
600                    mContentDescriptionDataType = mContext.getString(
601                            R.string.accessibility_data_connection_3g);
602                    break;
603                case TelephonyManager.NETWORK_TYPE_HSDPA:
604                case TelephonyManager.NETWORK_TYPE_HSUPA:
605                case TelephonyManager.NETWORK_TYPE_HSPA:
606                case TelephonyManager.NETWORK_TYPE_HSPAP:
607                    if (mHspaDataDistinguishable) {
608                        mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
609                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h;
610                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition];
611                        mContentDescriptionDataType = mContext.getString(
612                                R.string.accessibility_data_connection_3_5g);
613                    } else {
614                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
615                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
616                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
617                        mContentDescriptionDataType = mContext.getString(
618                                R.string.accessibility_data_connection_3g);
619                    }
620                    break;
621                case TelephonyManager.NETWORK_TYPE_CDMA:
622                    if (!mShowAtLeastThreeGees) {
623                        // display 1xRTT for IS95A/B
624                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
625                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
626                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
627                        mContentDescriptionDataType = mContext.getString(
628                                R.string.accessibility_data_connection_cdma);
629                        break;
630                    } else {
631                        // fall through
632                    }
633                case TelephonyManager.NETWORK_TYPE_1xRTT:
634                    if (!mShowAtLeastThreeGees) {
635                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
636                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
637                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
638                        mContentDescriptionDataType = mContext.getString(
639                                R.string.accessibility_data_connection_cdma);
640                        break;
641                    } else {
642                        // fall through
643                    }
644                case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
645                case TelephonyManager.NETWORK_TYPE_EVDO_A:
646                case TelephonyManager.NETWORK_TYPE_EVDO_B:
647                case TelephonyManager.NETWORK_TYPE_EHRPD:
648                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
649                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
650                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
651                    mContentDescriptionDataType = mContext.getString(
652                            R.string.accessibility_data_connection_3g);
653                    break;
654                case TelephonyManager.NETWORK_TYPE_LTE:
655                    boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
656                    if (show4GforLTE) {
657                        mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
658                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
659                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
660                        mContentDescriptionDataType = mContext.getString(
661                                R.string.accessibility_data_connection_4g);
662                    } else {
663                        mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition];
664                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte;
665                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition];
666                        mContentDescriptionDataType = mContext.getString(
667                                R.string.accessibility_data_connection_lte);
668                    }
669                    break;
670                default:
671                    if (!mShowAtLeastThreeGees) {
672                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
673                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g;
674                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition];
675                        mContentDescriptionDataType = mContext.getString(
676                                R.string.accessibility_data_connection_gprs);
677                    } else {
678                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
679                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
680                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
681                        mContentDescriptionDataType = mContext.getString(
682                                R.string.accessibility_data_connection_3g);
683                    }
684                    break;
685            }
686        }
687
688        if (isCdma()) {
689            if (isCdmaEri()) {
690                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
691                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
692            }
693        } else if (mPhone.isNetworkRoaming()) {
694                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
695                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
696        }
697    }
698
699    boolean isCdmaEri() {
700        if (mServiceState != null) {
701            final int iconIndex = mServiceState.getCdmaEriIconIndex();
702            if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
703                final int iconMode = mServiceState.getCdmaEriIconMode();
704                if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
705                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
706                    return true;
707                }
708            }
709        }
710        return false;
711    }
712
713    private final void updateDataIcon() {
714        int iconId;
715        boolean visible = true;
716
717        if (!isCdma()) {
718            // GSM case, we have to check also the sim state
719            if (mSimState == IccCardConstants.State.READY ||
720                    mSimState == IccCardConstants.State.UNKNOWN) {
721                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
722                    switch (mDataActivity) {
723                        case TelephonyManager.DATA_ACTIVITY_IN:
724                            iconId = mDataIconList[1];
725                            break;
726                        case TelephonyManager.DATA_ACTIVITY_OUT:
727                            iconId = mDataIconList[2];
728                            break;
729                        case TelephonyManager.DATA_ACTIVITY_INOUT:
730                            iconId = mDataIconList[3];
731                            break;
732                        default:
733                            iconId = mDataIconList[0];
734                            break;
735                    }
736                    mDataDirectionIconId = iconId;
737                } else {
738                    iconId = 0;
739                    visible = false;
740                }
741            } else {
742                iconId = R.drawable.stat_sys_no_sim;
743                visible = false; // no SIM? no data
744            }
745        } else {
746            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
747            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
748                switch (mDataActivity) {
749                    case TelephonyManager.DATA_ACTIVITY_IN:
750                        iconId = mDataIconList[1];
751                        break;
752                    case TelephonyManager.DATA_ACTIVITY_OUT:
753                        iconId = mDataIconList[2];
754                        break;
755                    case TelephonyManager.DATA_ACTIVITY_INOUT:
756                        iconId = mDataIconList[3];
757                        break;
758                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
759                    default:
760                        iconId = mDataIconList[0];
761                        break;
762                }
763            } else {
764                iconId = 0;
765                visible = false;
766            }
767        }
768
769        mDataDirectionIconId = iconId;
770        mDataConnected = visible;
771    }
772
773    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
774        if (false) {
775            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
776                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
777        }
778        StringBuilder str = new StringBuilder();
779        boolean something = false;
780        if (showPlmn && plmn != null) {
781            str.append(plmn);
782            something = true;
783        }
784        if (showSpn && spn != null) {
785            if (something) {
786                str.append(mNetworkNameSeparator);
787            }
788            str.append(spn);
789            something = true;
790        }
791        if (something) {
792            mNetworkName = str.toString();
793        } else {
794            mNetworkName = mNetworkNameDefault;
795        }
796    }
797
798    // ===== Wifi ===================================================================
799
800    class WifiHandler extends Handler {
801        @Override
802        public void handleMessage(Message msg) {
803            switch (msg.what) {
804                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
805                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
806                        mWifiChannel.sendMessage(Message.obtain(this,
807                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
808                    } else {
809                        Log.e(TAG, "Failed to connect to wifi");
810                    }
811                    break;
812                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
813                    if (msg.arg1 != mWifiActivity) {
814                        mWifiActivity = msg.arg1;
815                        refreshViews();
816                    }
817                    break;
818                default:
819                    //Ignore
820                    break;
821            }
822        }
823    }
824
825    private void updateWifiState(Intent intent) {
826        final String action = intent.getAction();
827        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
828            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
829                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
830
831        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
832            final NetworkInfo networkInfo = (NetworkInfo)
833                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
834            boolean wasConnected = mWifiConnected;
835            mWifiConnected = networkInfo != null && networkInfo.isConnected();
836            // If we just connected, grab the inintial signal strength and ssid
837            if (mWifiConnected && !wasConnected) {
838                // try getting it out of the intent first
839                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
840                if (info == null) {
841                    info = mWifiManager.getConnectionInfo();
842                }
843                if (info != null) {
844                    mWifiSsid = huntForSsid(info);
845                } else {
846                    mWifiSsid = null;
847                }
848            } else if (!mWifiConnected) {
849                mWifiSsid = null;
850            }
851        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
852            mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
853            mWifiLevel = WifiManager.calculateSignalLevel(
854                    mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
855        }
856
857        updateWifiIcons();
858    }
859
860    private void updateWifiIcons() {
861        if (mWifiConnected) {
862            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
863            mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
864            mContentDescriptionWifi = mContext.getString(
865                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
866        } else {
867            if (mDataAndWifiStacked) {
868                mWifiIconId = 0;
869                mQSWifiIconId = 0;
870            } else {
871                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
872                mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
873            }
874            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
875        }
876    }
877
878    private String huntForSsid(WifiInfo info) {
879        String ssid = info.getSSID();
880        if (ssid != null) {
881            return ssid;
882        }
883        // OK, it's not in the connectionInfo; we have to go hunting for it
884        List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
885        for (WifiConfiguration net : networks) {
886            if (net.networkId == info.getNetworkId()) {
887                return net.SSID;
888            }
889        }
890        return null;
891    }
892
893
894    // ===== Wimax ===================================================================
895    private final void updateWimaxState(Intent intent) {
896        final String action = intent.getAction();
897        boolean wasConnected = mWimaxConnected;
898        if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) {
899            int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
900                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
901            mIsWimaxEnabled = (wimaxStatus ==
902                    WimaxManagerConstants.NET_4G_STATE_ENABLED);
903        } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
904            mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
905        } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
906            mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
907                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
908            mWimaxExtraState = intent.getIntExtra(
909                    WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
910                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
911            mWimaxConnected = (mWimaxState ==
912                    WimaxManagerConstants.WIMAX_STATE_CONNECTED);
913            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
914        }
915        updateDataNetType();
916        updateWimaxIcons();
917    }
918
919    private void updateWimaxIcons() {
920        if (mIsWimaxEnabled) {
921            if (mWimaxConnected) {
922                if (mWimaxIdle)
923                    mWimaxIconId = WimaxIcons.WIMAX_IDLE;
924                else
925                    mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
926                mContentDescriptionWimax = mContext.getString(
927                        AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
928            } else {
929                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
930                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
931            }
932        } else {
933            mWimaxIconId = 0;
934        }
935    }
936
937    // ===== Full or limited Internet connectivity ==================================
938
939    private void updateConnectivity(Intent intent) {
940        if (CHATTY) {
941            Log.d(TAG, "updateConnectivity: intent=" + intent);
942        }
943
944        final ConnectivityManager connManager = (ConnectivityManager) mContext
945                .getSystemService(Context.CONNECTIVITY_SERVICE);
946        final NetworkInfo info = connManager.getActiveNetworkInfo();
947
948        // Are we connected at all, by any interface?
949        mConnected = info != null && info.isConnected();
950        if (mConnected) {
951            mConnectedNetworkType = info.getType();
952            mConnectedNetworkTypeName = info.getTypeName();
953        } else {
954            mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
955            mConnectedNetworkTypeName = null;
956        }
957
958        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
959
960        if (CHATTY) {
961            Log.d(TAG, "updateConnectivity: networkInfo=" + info);
962            Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
963        }
964
965        mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
966
967        if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
968            mBluetoothTethered = info.isConnected();
969        } else {
970            mBluetoothTethered = false;
971        }
972
973        // We want to update all the icons, all at once, for any condition change
974        updateDataNetType();
975        updateWimaxIcons();
976        updateDataIcon();
977        updateTelephonySignalStrength();
978        updateWifiIcons();
979    }
980
981
982    // ===== Update the views =======================================================
983
984    void refreshViews() {
985        Context context = mContext;
986
987        int combinedSignalIconId = 0;
988        String combinedLabel = "";
989        String wifiLabel = "";
990        String mobileLabel = "";
991        int N;
992        final boolean emergencyOnly = isEmergencyOnly();
993
994        if (!mHasMobileDataFeature) {
995            mDataSignalIconId = mPhoneSignalIconId = 0;
996            mQSPhoneSignalIconId = 0;
997            mobileLabel = "";
998        } else {
999            // We want to show the carrier name if in service and either:
1000            //   - We are connected to mobile data, or
1001            //   - We are not connected to mobile data, as long as the *reason* packets are not
1002            //     being routed over that link is that we have better connectivity via wifi.
1003            // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
1004            // is connected, we show nothing.
1005            // Otherwise (nothing connected) we show "No internet connection".
1006
1007            if (mDataConnected) {
1008                mobileLabel = mNetworkName;
1009            } else if (mConnected || emergencyOnly) {
1010                if (hasService() || emergencyOnly) {
1011                    // The isEmergencyOnly test covers the case of a phone with no SIM
1012                    mobileLabel = mNetworkName;
1013                } else {
1014                    // Tablets, basically
1015                    mobileLabel = "";
1016                }
1017            } else {
1018                mobileLabel
1019                    = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1020            }
1021
1022            // Now for things that should only be shown when actually using mobile data.
1023            if (mDataConnected) {
1024                combinedSignalIconId = mDataSignalIconId;
1025
1026                combinedLabel = mobileLabel;
1027                combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
1028                mContentDescriptionCombinedSignal = mContentDescriptionDataType;
1029            }
1030        }
1031
1032        if (mWifiConnected) {
1033            if (mWifiSsid == null) {
1034                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
1035            } else {
1036                wifiLabel = mWifiSsid;
1037                if (DEBUG) {
1038                    wifiLabel += "xxxxXXXXxxxxXXXX";
1039                }
1040            }
1041
1042            combinedLabel = wifiLabel;
1043            combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
1044            mContentDescriptionCombinedSignal = mContentDescriptionWifi;
1045        } else {
1046            if (mHasMobileDataFeature) {
1047                wifiLabel = "";
1048            } else {
1049                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1050            }
1051        }
1052
1053        if (mBluetoothTethered) {
1054            combinedLabel = mContext.getString(R.string.bluetooth_tethered);
1055            combinedSignalIconId = mBluetoothTetherIconId;
1056            mContentDescriptionCombinedSignal = mContext.getString(
1057                    R.string.accessibility_bluetooth_tether);
1058        }
1059
1060        final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
1061        if (ethernetConnected) {
1062            combinedLabel = context.getString(R.string.ethernet_label);
1063        }
1064
1065        if (mAirplaneMode &&
1066                (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
1067            // Only display the flight-mode icon if not in "emergency calls only" mode.
1068
1069            // look again; your radios are now airplanes
1070            mContentDescriptionPhoneSignal = mContext.getString(
1071                    R.string.accessibility_airplane_mode);
1072            mAirplaneIconId = FLIGHT_MODE_ICON;
1073            mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
1074            mQSPhoneSignalIconId = 0;
1075
1076            // combined values from connected wifi take precedence over airplane mode
1077            if (mWifiConnected) {
1078                // Suppress "No internet connection." from mobile if wifi connected.
1079                mobileLabel = "";
1080            } else {
1081                if (mHasMobileDataFeature) {
1082                    // let the mobile icon show "No internet connection."
1083                    wifiLabel = "";
1084                } else {
1085                    wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1086                    combinedLabel = wifiLabel;
1087                }
1088                mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
1089                combinedSignalIconId = mDataSignalIconId;
1090            }
1091        }
1092        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
1093            // pretty much totally disconnected
1094
1095            combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
1096            // On devices without mobile radios, we want to show the wifi icon
1097            combinedSignalIconId =
1098                mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
1099            mContentDescriptionCombinedSignal = mHasMobileDataFeature
1100                ? mContentDescriptionDataType : mContentDescriptionWifi;
1101
1102            mDataTypeIconId = 0;
1103            mQSDataTypeIconId = 0;
1104            if (isCdma()) {
1105                if (isCdmaEri()) {
1106                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
1107                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
1108                }
1109            } else if (mPhone.isNetworkRoaming()) {
1110                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
1111                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
1112            }
1113        }
1114
1115        if (DEBUG) {
1116            Log.d(TAG, "refreshViews connected={"
1117                    + (mWifiConnected?" wifi":"")
1118                    + (mDataConnected?" data":"")
1119                    + " } level="
1120                    + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
1121                    + " combinedSignalIconId=0x"
1122                    + Integer.toHexString(combinedSignalIconId)
1123                    + "/" + getResourceName(combinedSignalIconId)
1124                    + " mobileLabel=" + mobileLabel
1125                    + " wifiLabel=" + wifiLabel
1126                    + " emergencyOnly=" + emergencyOnly
1127                    + " combinedLabel=" + combinedLabel
1128                    + " mAirplaneMode=" + mAirplaneMode
1129                    + " mDataActivity=" + mDataActivity
1130                    + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
1131                    + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId)
1132                    + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
1133                    + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
1134                    + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
1135                    + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId)
1136                    + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
1137                    + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId)
1138                    + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
1139        }
1140
1141        // update QS
1142        for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
1143            notifySignalsChangedCallbacks(cb);
1144        }
1145
1146        if (mLastPhoneSignalIconId          != mPhoneSignalIconId
1147         || mLastWifiIconId                 != mWifiIconId
1148         || mLastWimaxIconId                != mWimaxIconId
1149         || mLastDataTypeIconId             != mDataTypeIconId
1150         || mLastAirplaneMode               != mAirplaneMode
1151         || mLastLocale                     != mLocale)
1152        {
1153            // NB: the mLast*s will be updated later
1154            for (SignalCluster cluster : mSignalClusters) {
1155                refreshSignalCluster(cluster);
1156            }
1157        }
1158
1159        if (mLastAirplaneMode != mAirplaneMode) {
1160            mLastAirplaneMode = mAirplaneMode;
1161        }
1162
1163        if (mLastLocale != mLocale) {
1164            mLastLocale = mLocale;
1165        }
1166
1167        // the phone icon on phones
1168        if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
1169            mLastPhoneSignalIconId = mPhoneSignalIconId;
1170        }
1171
1172        // the data icon on phones
1173        if (mLastDataDirectionIconId != mDataDirectionIconId) {
1174            mLastDataDirectionIconId = mDataDirectionIconId;
1175        }
1176
1177        // the wifi icon on phones
1178        if (mLastWifiIconId != mWifiIconId) {
1179            mLastWifiIconId = mWifiIconId;
1180        }
1181
1182        // the wimax icon on phones
1183        if (mLastWimaxIconId != mWimaxIconId) {
1184            mLastWimaxIconId = mWimaxIconId;
1185        }
1186        // the combined data signal icon
1187        if (mLastCombinedSignalIconId != combinedSignalIconId) {
1188            mLastCombinedSignalIconId = combinedSignalIconId;
1189        }
1190
1191        // the data network type overlay
1192        if (mLastDataTypeIconId != mDataTypeIconId) {
1193            mLastDataTypeIconId = mDataTypeIconId;
1194        }
1195
1196        // the combinedLabel in the notification panel
1197        if (!mLastCombinedLabel.equals(combinedLabel)) {
1198            mLastCombinedLabel = combinedLabel;
1199            N = mCombinedLabelViews.size();
1200            for (int i=0; i<N; i++) {
1201                TextView v = mCombinedLabelViews.get(i);
1202                v.setText(combinedLabel);
1203            }
1204        }
1205
1206        // wifi label
1207        N = mWifiLabelViews.size();
1208        for (int i=0; i<N; i++) {
1209            TextView v = mWifiLabelViews.get(i);
1210            v.setText(wifiLabel);
1211            if ("".equals(wifiLabel)) {
1212                v.setVisibility(View.GONE);
1213            } else {
1214                v.setVisibility(View.VISIBLE);
1215            }
1216        }
1217
1218        // mobile label
1219        N = mMobileLabelViews.size();
1220        for (int i=0; i<N; i++) {
1221            TextView v = mMobileLabelViews.get(i);
1222            v.setText(mobileLabel);
1223            if ("".equals(mobileLabel)) {
1224                v.setVisibility(View.GONE);
1225            } else {
1226                v.setVisibility(View.VISIBLE);
1227            }
1228        }
1229
1230        // e-call label
1231        N = mEmergencyLabelViews.size();
1232        for (int i=0; i<N; i++) {
1233            TextView v = mEmergencyLabelViews.get(i);
1234            if (!emergencyOnly) {
1235                v.setVisibility(View.GONE);
1236            } else {
1237                v.setText(mobileLabel); // comes from the telephony stack
1238                v.setVisibility(View.VISIBLE);
1239            }
1240        }
1241    }
1242
1243    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1244        pw.println("NetworkController state:");
1245        pw.println(String.format("  %s network type %d (%s)",
1246                mConnected?"CONNECTED":"DISCONNECTED",
1247                mConnectedNetworkType, mConnectedNetworkTypeName));
1248        pw.println("  - telephony ------");
1249        pw.print("  hasVoiceCallingFeature()=");
1250        pw.println(hasVoiceCallingFeature());
1251        pw.print("  hasService()=");
1252        pw.println(hasService());
1253        pw.print("  mHspaDataDistinguishable=");
1254        pw.println(mHspaDataDistinguishable);
1255        pw.print("  mDataConnected=");
1256        pw.println(mDataConnected);
1257        pw.print("  mSimState=");
1258        pw.println(mSimState);
1259        pw.print("  mPhoneState=");
1260        pw.println(mPhoneState);
1261        pw.print("  mDataState=");
1262        pw.println(mDataState);
1263        pw.print("  mDataActivity=");
1264        pw.println(mDataActivity);
1265        pw.print("  mDataNetType=");
1266        pw.print(mDataNetType);
1267        pw.print("/");
1268        pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
1269        pw.print("  mServiceState=");
1270        pw.println(mServiceState);
1271        pw.print("  mSignalStrength=");
1272        pw.println(mSignalStrength);
1273        pw.print("  mLastSignalLevel=");
1274        pw.println(mLastSignalLevel);
1275        pw.print("  mNetworkName=");
1276        pw.println(mNetworkName);
1277        pw.print("  mNetworkNameDefault=");
1278        pw.println(mNetworkNameDefault);
1279        pw.print("  mNetworkNameSeparator=");
1280        pw.println(mNetworkNameSeparator.replace("\n","\\n"));
1281        pw.print("  mPhoneSignalIconId=0x");
1282        pw.print(Integer.toHexString(mPhoneSignalIconId));
1283        pw.print("/");
1284        pw.print("  mQSPhoneSignalIconId=0x");
1285        pw.print(Integer.toHexString(mQSPhoneSignalIconId));
1286        pw.print("/");
1287        pw.println(getResourceName(mPhoneSignalIconId));
1288        pw.print("  mDataDirectionIconId=");
1289        pw.print(Integer.toHexString(mDataDirectionIconId));
1290        pw.print("/");
1291        pw.println(getResourceName(mDataDirectionIconId));
1292        pw.print("  mDataSignalIconId=");
1293        pw.print(Integer.toHexString(mDataSignalIconId));
1294        pw.print("/");
1295        pw.println(getResourceName(mDataSignalIconId));
1296        pw.print("  mDataTypeIconId=");
1297        pw.print(Integer.toHexString(mDataTypeIconId));
1298        pw.print("/");
1299        pw.println(getResourceName(mDataTypeIconId));
1300        pw.print("  mQSDataTypeIconId=");
1301        pw.print(Integer.toHexString(mQSDataTypeIconId));
1302        pw.print("/");
1303        pw.println(getResourceName(mQSDataTypeIconId));
1304
1305        pw.println("  - wifi ------");
1306        pw.print("  mWifiEnabled=");
1307        pw.println(mWifiEnabled);
1308        pw.print("  mWifiConnected=");
1309        pw.println(mWifiConnected);
1310        pw.print("  mWifiRssi=");
1311        pw.println(mWifiRssi);
1312        pw.print("  mWifiLevel=");
1313        pw.println(mWifiLevel);
1314        pw.print("  mWifiSsid=");
1315        pw.println(mWifiSsid);
1316        pw.println(String.format("  mWifiIconId=0x%08x/%s",
1317                    mWifiIconId, getResourceName(mWifiIconId)));
1318        pw.println(String.format("  mQSWifiIconId=0x%08x/%s",
1319                    mQSWifiIconId, getResourceName(mQSWifiIconId)));
1320        pw.print("  mWifiActivity=");
1321        pw.println(mWifiActivity);
1322
1323        if (mWimaxSupported) {
1324            pw.println("  - wimax ------");
1325            pw.print("  mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
1326            pw.print("  mWimaxConnected="); pw.println(mWimaxConnected);
1327            pw.print("  mWimaxIdle="); pw.println(mWimaxIdle);
1328            pw.println(String.format("  mWimaxIconId=0x%08x/%s",
1329                        mWimaxIconId, getResourceName(mWimaxIconId)));
1330            pw.println(String.format("  mWimaxSignal=%d", mWimaxSignal));
1331            pw.println(String.format("  mWimaxState=%d", mWimaxState));
1332            pw.println(String.format("  mWimaxExtraState=%d", mWimaxExtraState));
1333        }
1334
1335        pw.println("  - Bluetooth ----");
1336        pw.print("  mBtReverseTethered=");
1337        pw.println(mBluetoothTethered);
1338
1339        pw.println("  - connectivity ------");
1340        pw.print("  mInetCondition=");
1341        pw.println(mInetCondition);
1342
1343        pw.println("  - icons ------");
1344        pw.print("  mLastPhoneSignalIconId=0x");
1345        pw.print(Integer.toHexString(mLastPhoneSignalIconId));
1346        pw.print("/");
1347        pw.println(getResourceName(mLastPhoneSignalIconId));
1348        pw.print("  mLastDataDirectionIconId=0x");
1349        pw.print(Integer.toHexString(mLastDataDirectionIconId));
1350        pw.print("/");
1351        pw.println(getResourceName(mLastDataDirectionIconId));
1352        pw.print("  mLastWifiIconId=0x");
1353        pw.print(Integer.toHexString(mLastWifiIconId));
1354        pw.print("/");
1355        pw.println(getResourceName(mLastWifiIconId));
1356        pw.print("  mLastCombinedSignalIconId=0x");
1357        pw.print(Integer.toHexString(mLastCombinedSignalIconId));
1358        pw.print("/");
1359        pw.println(getResourceName(mLastCombinedSignalIconId));
1360        pw.print("  mLastDataTypeIconId=0x");
1361        pw.print(Integer.toHexString(mLastDataTypeIconId));
1362        pw.print("/");
1363        pw.println(getResourceName(mLastDataTypeIconId));
1364        pw.print("  mLastCombinedLabel=");
1365        pw.print(mLastCombinedLabel);
1366        pw.println("");
1367    }
1368
1369    private String getResourceName(int resId) {
1370        if (resId != 0) {
1371            final Resources res = mContext.getResources();
1372            try {
1373                return res.getResourceName(resId);
1374            } catch (android.content.res.Resources.NotFoundException ex) {
1375                return "(unknown)";
1376            }
1377        } else {
1378            return "(null)";
1379        }
1380    }
1381
1382    private boolean mDemoMode;
1383    private int mDemoInetCondition;
1384    private int mDemoWifiLevel;
1385    private int mDemoDataTypeIconId;
1386    private int mDemoMobileLevel;
1387
1388    @Override
1389    public void dispatchDemoCommand(String command, Bundle args) {
1390        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
1391            mDemoMode = true;
1392            mDemoWifiLevel = mWifiLevel;
1393            mDemoInetCondition = mInetCondition;
1394            mDemoDataTypeIconId = mDataTypeIconId;
1395            mDemoMobileLevel = mLastSignalLevel;
1396        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
1397            mDemoMode = false;
1398            for (SignalCluster cluster : mSignalClusters) {
1399                refreshSignalCluster(cluster);
1400            }
1401        } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
1402            String airplane = args.getString("airplane");
1403            if (airplane != null) {
1404                boolean show = airplane.equals("show");
1405                for (SignalCluster cluster : mSignalClusters) {
1406                    cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON);
1407                }
1408            }
1409            String fully = args.getString("fully");
1410            if (fully != null) {
1411                mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
1412            }
1413            String wifi = args.getString("wifi");
1414            if (wifi != null) {
1415                boolean show = wifi.equals("show");
1416                String level = args.getString("level");
1417                if (level != null) {
1418                    mDemoWifiLevel = level.equals("null") ? -1
1419                            : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
1420                }
1421                int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null
1422                        : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
1423                for (SignalCluster cluster : mSignalClusters) {
1424                    cluster.setWifiIndicators(
1425                            show,
1426                            iconId,
1427                            "Demo");
1428                }
1429            }
1430            String mobile = args.getString("mobile");
1431            if (mobile != null) {
1432                boolean show = mobile.equals("show");
1433                String datatype = args.getString("datatype");
1434                if (datatype != null) {
1435                    mDemoDataTypeIconId =
1436                            datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x :
1437                            datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g :
1438                            datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g :
1439                            datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e :
1440                            datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g :
1441                            datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h :
1442                            datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte :
1443                            datatype.equals("roam")
1444                                    ? R.drawable.stat_sys_data_fully_connected_roam :
1445                            0;
1446                }
1447                int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
1448                String level = args.getString("level");
1449                if (level != null) {
1450                    mDemoMobileLevel = level.equals("null") ? -1
1451                            : Math.min(Integer.parseInt(level), icons[0].length - 1);
1452                }
1453                int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null :
1454                        icons[mDemoInetCondition][mDemoMobileLevel];
1455                for (SignalCluster cluster : mSignalClusters) {
1456                    cluster.setMobileDataIndicators(
1457                            show,
1458                            iconId,
1459                            mDemoDataTypeIconId,
1460                            "Demo",
1461                            "Demo");
1462                }
1463            }
1464        }
1465    }
1466}
1467