diff options
17 files changed, 1433 insertions, 1397 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 178590be3b23..80ddd4a8bec1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -29,7 +29,8 @@ import com.android.systemui.qs.QSTile;  import com.android.systemui.qs.QSTileView;  import com.android.systemui.qs.SignalTileView;  import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.NetworkController.DataUsageInfo; +import com.android.systemui.statusbar.policy.NetworkController.MobileDataController; +import com.android.systemui.statusbar.policy.NetworkController.MobileDataController.DataUsageInfo;  import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;  /** Quick settings tile: Cellular **/ @@ -38,11 +39,13 @@ public class CellularTile extends QSTile<QSTile.SignalState> {              "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));      private final NetworkController mController; +    private final MobileDataController mDataController;      private final CellularDetailAdapter mDetailAdapter;      public CellularTile(Host host) {          super(host);          mController = host.getNetworkController(); +        mDataController = mController.getMobileDataController();          mDetailAdapter = new CellularDetailAdapter();      } @@ -72,7 +75,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {      @Override      protected void handleClick() { -        if (mController.isMobileDataSupported()) { +        if (mDataController.isMobileDataSupported()) {              showDetail(true);          } else {              mHost.startSettingsActivity(CELLULAR_SETTINGS); @@ -199,7 +202,8 @@ public class CellularTile extends QSTile<QSTile.SignalState> {          @Override          public Boolean getToggleState() { -            return mController.isMobileDataSupported() ? mController.isMobileDataEnabled() : null; +            return mDataController.isMobileDataSupported() +                    ? mDataController.isMobileDataEnabled() : null;          }          @Override @@ -209,7 +213,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {          @Override          public void setToggleState(boolean state) { -            mController.setMobileDataEnabled(state); +            mDataController.setMobileDataEnabled(state);          }          @Override @@ -217,7 +221,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {              final DataUsageDetailView v = (DataUsageDetailView) (convertView != null                      ? convertView                      : LayoutInflater.from(mContext).inflate(R.layout.data_usage, parent, false)); -            final DataUsageInfo info = mController.getDataUsageInfo(); +            final DataUsageInfo info = mDataController.getDataUsageInfo();              if (info == null) return v;              v.bind(info);              return v; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java index 7bdb58f2daa7..eb816b759c91 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java @@ -20,7 +20,6 @@ import android.content.Context;  import android.content.res.Configuration;  import android.content.res.Resources;  import android.util.AttributeSet; -import android.util.TypedValue;  import android.view.View;  import android.widget.LinearLayout;  import android.widget.TextView; @@ -61,7 +60,7 @@ public class DataUsageDetailView extends LinearLayout {                  R.dimen.qs_data_usage_text_size);      } -    public void bind(NetworkController.DataUsageInfo info) { +    public void bind(NetworkController.MobileDataController.DataUsageInfo info) {          final Resources res = mContext.getResources();          final int titleId;          final long bytes; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 7aa884effe7a..4fb1189dee90 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -31,7 +31,8 @@ import com.android.systemui.qs.QSTile;  import com.android.systemui.qs.QSTileView;  import com.android.systemui.qs.SignalTileView;  import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.NetworkController.AccessPoint; +import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; +import com.android.systemui.statusbar.policy.NetworkController.AccessPointController.AccessPoint;  import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;  /** Quick settings tile: Wifi **/ @@ -39,12 +40,14 @@ public class WifiTile extends QSTile<QSTile.SignalState> {      private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);      private final NetworkController mController; +    private final AccessPointController mWifiController;      private final WifiDetailAdapter mDetailAdapter;      private final QSTile.SignalState mStateBeforeClick = newTileState();      public WifiTile(Host host) {          super(host);          mController = host.getNetworkController(); +        mWifiController = mController.getAccessPointController();          mDetailAdapter = new WifiDetailAdapter();      } @@ -62,10 +65,10 @@ public class WifiTile extends QSTile<QSTile.SignalState> {      public void setListening(boolean listening) {          if (listening) {              mController.addNetworkSignalChangedCallback(mCallback); -            mController.addAccessPointCallback(mDetailAdapter); +            mWifiController.addAccessPointCallback(mDetailAdapter);          } else {              mController.removeNetworkSignalChangedCallback(mCallback); -            mController.removeAccessPointCallback(mDetailAdapter); +            mWifiController.removeAccessPointCallback(mDetailAdapter);          }      } @@ -87,7 +90,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {      @Override      protected void handleSecondaryClick() { -        if (!mController.canConfigWifi()) { +        if (!mWifiController.canConfigWifi()) {              mHost.startSettingsActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));              return;          } @@ -231,7 +234,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {      };      private final class WifiDetailAdapter implements DetailAdapter, -            NetworkController.AccessPointCallback, QSDetailItems.Callback { +            NetworkController.AccessPointController.AccessPointCallback, QSDetailItems.Callback {          private QSDetailItems mItems;          private AccessPoint[] mAccessPoints; @@ -261,7 +264,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {          public View createDetailView(Context context, View convertView, ViewGroup parent) {              if (DEBUG) Log.d(TAG, "createDetailView convertView=" + (convertView != null));              mAccessPoints = null; -            mController.scanForAccessPoints(); +            mWifiController.scanForAccessPoints();              fireScanStateChanged(true);              mItems = QSDetailItems.convertOrInflate(context, convertView, parent);              mItems.setTagSuffix("Wifi"); @@ -287,7 +290,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {              if (item == null || item.tag == null) return;              final AccessPoint ap = (AccessPoint) item.tag;              if (!ap.isConnected) { -                if (mController.connect(ap)) { +                if (mWifiController.connect(ap)) {                      mHost.collapsePanels();                  }              } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index 9154a487e8ac..418c57f8f15c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -48,6 +48,7 @@ public class SignalClusterView      private int mMobileStrengthId = 0, mMobileTypeId = 0;      private boolean mIsAirplaneMode = false;      private int mAirplaneIconId = 0; +    private int mAirplaneContentDescription;      private String mWifiDescription, mMobileDescription, mMobileTypeDescription;      private boolean mIsMobileTypeIconWide; @@ -160,9 +161,10 @@ public class SignalClusterView      }      @Override -    public void setIsAirplaneMode(boolean is, int airplaneIconId) { +    public void setIsAirplaneMode(boolean is, int airplaneIconId, int contentDescription) {          mIsAirplaneMode = is;          mAirplaneIconId = airplaneIconId; +        mAirplaneContentDescription = contentDescription;          apply();      } @@ -236,6 +238,8 @@ public class SignalClusterView          if (mIsAirplaneMode) {              mAirplane.setImageResource(mAirplaneIconId); +            mAirplane.setContentDescription(mAirplaneContentDescription != 0 ? +                    mContext.getString(mAirplaneContentDescription) : "");              mAirplane.setVisibility(View.VISIBLE);          } else {              mAirplane.setVisibility(View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 3b2d3cb0b13c..9a1ac4949272 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -79,6 +79,7 @@ import android.provider.Settings;  import android.service.notification.NotificationListenerService;  import android.service.notification.NotificationListenerService.RankingMap;  import android.service.notification.StatusBarNotification; +import android.text.TextUtils;  import android.util.ArraySet;  import android.util.DisplayMetrics;  import android.util.EventLog; @@ -821,7 +822,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,          signalClusterQs.setNetworkController(mNetworkController);          final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();          if (isAPhone) { -            mNetworkController.addEmergencyLabelView(mHeader); +            mNetworkController.addEmergencyListener(new NetworkControllerImpl.EmergencyListener() { +                @Override +                public void setEmergencyCallsOnly(boolean emergencyOnly) { +                    mHeader.setShowEmergencyCallsOnly(emergencyOnly); +                } +            });          }          mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label); @@ -830,13 +836,19 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,          if (mShowCarrierInPanel) {              mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE); -            // for mobile devices, we always show mobile connection info here (SPN/PLMN) -            // for other devices, we show whatever network is connected -            if (mNetworkController.hasMobileDataFeature()) { -                mNetworkController.addMobileLabelView(mCarrierLabel); -            } else { -                mNetworkController.addCombinedLabelView(mCarrierLabel); -            } +            mNetworkController.addCarrierLabel(new NetworkControllerImpl.CarrierLabelListener() { +                @Override +                public void setCarrierLabel(String label) { +                    mCarrierLabel.setText(label); +                    if (mNetworkController.hasMobileDataFeature()) { +                        if (TextUtils.isEmpty(label)) { +                            mCarrierLabel.setVisibility(View.GONE); +                        } else { +                            mCarrierLabel.setVisibility(View.VISIBLE); +                        } +                    } +                } +            });              // set up the dynamic hide/show of the label              // TODO: uncomment, handle this for the Stack scroller aswell diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index 45a138610b1c..8ce608c016b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -122,7 +122,7 @@ public class QSTileHost implements QSTile.Host {                      tile.userSwitch(newUserId);                  }                  mSecurity.onUserSwitched(newUserId); -                mNetwork.onUserSwitched(newUserId); +                mNetwork.getAccessPointController().onUserSwitched(newUserId);                  mObserver.register();              }          }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java index 0a385d72666b..6fec97e09aac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java @@ -36,15 +36,13 @@ import android.util.ArraySet;  import android.util.Log;  import com.android.systemui.R; -import com.android.systemui.statusbar.policy.NetworkController.AccessPoint; -import com.android.systemui.statusbar.policy.NetworkController.AccessPointCallback;  import java.util.ArrayList;  import java.util.Collections;  import java.util.Comparator;  import java.util.List; -public class AccessPointController { +public class AccessPointControllerImpl implements NetworkController.AccessPointController {      private static final String TAG = "AccessPointController";      private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -69,7 +67,7 @@ public class AccessPointController {      private boolean mScanning;      private int mCurrentUser; -    public AccessPointController(Context context) { +    public AccessPointControllerImpl(Context context) {          mContext = context;          mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);          mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); @@ -81,25 +79,28 @@ public class AccessPointController {                  new UserHandle(mCurrentUser));      } -    void onUserSwitched(int newUserId) { +    public void onUserSwitched(int newUserId) {          mCurrentUser = newUserId;      } -    public void addCallback(AccessPointCallback callback) { +    @Override +    public void addAccessPointCallback(AccessPointCallback callback) {          if (callback == null || mCallbacks.contains(callback)) return;          if (DEBUG) Log.d(TAG, "addCallback " + callback);          mCallbacks.add(callback);          mReceiver.setListening(!mCallbacks.isEmpty());      } -    public void removeCallback(AccessPointCallback callback) { +    @Override +    public void removeAccessPointCallback(AccessPointCallback callback) {          if (callback == null) return;          if (DEBUG) Log.d(TAG, "removeCallback " + callback);          mCallbacks.remove(callback);          mReceiver.setListening(!mCallbacks.isEmpty());      } -    public void scan() { +    @Override +    public void scanForAccessPoints() {          if (mScanning) return;          if (DEBUG) Log.d(TAG, "scan!");          mScanning = mWifiManager.startScan(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java index 7ac2a986c75d..b7c74e3afadf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java @@ -33,11 +33,5 @@ public class AccessibilityContentDescriptions {          R.string.accessibility_wifi_three_bars,          R.string.accessibility_wifi_signal_full      }; -    static final int[] WIMAX_CONNECTION_STRENGTH = { -        R.string.accessibility_no_wimax, -        R.string.accessibility_wimax_one_bar, -        R.string.accessibility_wimax_two_bars, -        R.string.accessibility_wimax_three_bars, -        R.string.accessibility_wimax_signal_full -    }; +    static final int WIFI_NO_CONNECTION = R.string.accessibility_no_wifi;  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java index 33d68bf37f09..20f0a83d38b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java @@ -38,12 +38,10 @@ import android.text.format.DateUtils;  import android.text.format.Time;  import android.util.Log; -import com.android.systemui.statusbar.policy.NetworkController.DataUsageInfo; -  import java.util.Date;  import java.util.Locale; -public class MobileDataController { +public class MobileDataControllerImpl implements NetworkController.MobileDataController {      private static final String TAG = "MobileDataController";      private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -61,8 +59,9 @@ public class MobileDataController {      private INetworkStatsSession mSession;      private Callback mCallback; +    private NetworkControllerImpl mNetworkController; -    public MobileDataController(Context context) { +    public MobileDataControllerImpl(Context context) {          mContext = context;          mTelephonyManager = TelephonyManager.from(context);          mConnectivityManager = ConnectivityManager.from(context); @@ -71,6 +70,10 @@ public class MobileDataController {          mPolicyManager = NetworkPolicyManager.from(mContext);      } +    public void setNetworkController(NetworkControllerImpl networkController) { +        mNetworkController = networkController; +    } +      private INetworkStatsSession getSession() {          if (mSession == null) {              try { @@ -155,6 +158,9 @@ public class MobileDataController {              } else {                  usage.warningLevel = DEFAULT_WARNING_LEVEL;              } +            if (usage != null) { +                usage.carrier = mNetworkController.getMobileNetworkName(); +            }              return usage;          } catch (RemoteException e) {              return warn("remote call failed"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index bb29d01e2557..b024f58cbd27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -22,6 +22,8 @@ public interface NetworkController {      void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);      void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);      void setWifiEnabled(boolean enabled); +    AccessPointController getAccessPointController(); +    MobileDataController getMobileDataController();      public interface NetworkSignalChangedCallback {          void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId, @@ -36,38 +38,50 @@ public interface NetworkController {          void onMobileDataEnabled(boolean enabled);      } -    void addAccessPointCallback(AccessPointCallback callback); -    void removeAccessPointCallback(AccessPointCallback callback); -    void scanForAccessPoints(); -    boolean connect(AccessPoint ap); -    boolean isMobileDataSupported(); -    boolean isMobileDataEnabled(); -    void setMobileDataEnabled(boolean enabled); -    DataUsageInfo getDataUsageInfo(); -    boolean canConfigWifi(); -    void onUserSwitched(int newUserId); +    /** +     * Tracks changes in access points.  Allows listening for changes, scanning for new APs, +     * and connecting to new ones. +     */ +    public interface AccessPointController { +        void addAccessPointCallback(AccessPointCallback callback); +        void removeAccessPointCallback(AccessPointCallback callback); +        void scanForAccessPoints(); +        boolean connect(AccessPoint ap); +        boolean canConfigWifi(); +        void onUserSwitched(int newUserId); -    public interface AccessPointCallback { -        void onAccessPointsChanged(AccessPoint[] accessPoints); -    } +        public interface AccessPointCallback { +            void onAccessPointsChanged(AccessPoint[] accessPoints); +        } -    public static class AccessPoint { -        public static final int NO_NETWORK = -1;  // see WifiManager +        public static class AccessPoint { +            public static final int NO_NETWORK = -1;  // see WifiManager -        public int networkId; -        public int iconId; -        public String ssid; -        public boolean isConnected; -        public boolean isConfigured; -        public boolean hasSecurity; -        public int level;  // 0 - 5 +            public int networkId; +            public int iconId; +            public String ssid; +            public boolean isConnected; +            public boolean isConfigured; +            public boolean hasSecurity; +            public int level;  // 0 - 5 +        }      } -    public static class DataUsageInfo { -        public String carrier; -        public String period; -        public long limitLevel; -        public long warningLevel; -        public long usageLevel; +    /** +     * Tracks mobile data support and usage. +     */ +    public interface MobileDataController { +        boolean isMobileDataSupported(); +        boolean isMobileDataEnabled(); +        void setMobileDataEnabled(boolean enabled); +        DataUsageInfo getDataUsageInfo(); + +        public static class DataUsageInfo { +            public String carrier; +            public String period; +            public long limitLevel; +            public long warningLevel; +            public long usageLevel; +        }      }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 07762a4604c0..5a97c75e313b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -26,7 +26,6 @@ import android.net.NetworkInfo;  import android.net.wifi.WifiConfiguration;  import android.net.wifi.WifiInfo;  import android.net.wifi.WifiManager; -import android.net.wimax.WimaxManagerConstants;  import android.os.AsyncTask;  import android.os.Bundle;  import android.os.Handler; @@ -37,9 +36,8 @@ import android.telephony.PhoneStateListener;  import android.telephony.ServiceState;  import android.telephony.SignalStrength;  import android.telephony.TelephonyManager; +import android.text.format.DateFormat;  import android.util.Log; -import android.view.View; -import android.widget.TextView;  import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.telephony.IccCardConstants; @@ -48,130 +46,66 @@ import com.android.internal.telephony.cdma.EriInfo;  import com.android.internal.util.AsyncChannel;  import com.android.systemui.DemoMode;  import com.android.systemui.R; -import com.android.systemui.statusbar.phone.StatusBarHeaderView;  import java.io.FileDescriptor;  import java.io.PrintWriter;  import java.util.ArrayList; +import java.util.HashMap;  import java.util.List;  import java.util.Locale; +import java.util.Map; +import java.util.Objects;  /** Platform implementation of the network controller. **/  public class NetworkControllerImpl extends BroadcastReceiver          implements NetworkController, DemoMode {      // debug -    static final String TAG = "StatusBar.NetworkController"; -    static final boolean DEBUG = false; -    static final boolean CHATTY = false; // additional diagnostics, but not logspew - -    // telephony -    boolean mHspaDataDistinguishable; -    final TelephonyManager mPhone; -    boolean mDataConnected; -    IccCardConstants.State mSimState = IccCardConstants.State.READY; -    int mPhoneState = TelephonyManager.CALL_STATE_IDLE; -    int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN; -    int mDataState = TelephonyManager.DATA_DISCONNECTED; -    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; -    ServiceState mServiceState; -    SignalStrength mSignalStrength; -    int[] mDataIconList = TelephonyIcons.DATA_G[0]; -    String mNetworkName; -    String mNetworkNameDefault; -    String mNetworkNameSeparator; -    int mPhoneSignalIconId; -    int mQSPhoneSignalIconId; -    int mDataDirectionIconId; // data + data direction on phones -    int mDataSignalIconId; -    int mDataTypeIconId; -    int mQSDataTypeIconId; -    int mAirplaneIconId; -    boolean mDataActive; -    boolean mNoSim; -    int mLastSignalLevel; -    boolean mShowPhoneRSSIForData = false; -    boolean mShowAtLeastThreeGees = false; -    boolean mAlwaysShowCdmaRssi = false; - -    String mContentDescriptionPhoneSignal; -    String mContentDescriptionWifi; -    String mContentDescriptionWimax; -    String mContentDescriptionCombinedSignal; -    String mContentDescriptionDataType; - -    // wifi -    final WifiManager mWifiManager; -    AsyncChannel mWifiChannel; -    boolean mWifiEnabled, mWifiConnected; -    int mWifiRssi, mWifiLevel; -    String mWifiSsid; -    int mWifiIconId = 0; -    int mQSWifiIconId = 0; -    int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE; +    static final String TAG = "NetworkController"; +    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); +    // additional diagnostics, but not logspew +    static final boolean CHATTY =  Log.isLoggable(TAG + ".Chat", Log.DEBUG); +    // Save the previous states of all SignalController state info. +    static final boolean RECORD_HISTORY = true; +    // How many to save, must be a power of 2. +    static final int HISTORY_SIZE = 16; + +    private static final int INET_CONDITION_THRESHOLD = 50; + +    private final Context mContext; +    private final TelephonyManager mPhone; +    private final WifiManager mWifiManager; +    private final ConnectivityManager mConnectivityManager; +    private final boolean mHasMobileDataFeature; + +    // Subcontrollers. +    @VisibleForTesting +    final WifiSignalController mWifiSignalController; +    @VisibleForTesting +    final MobileSignalController mMobileSignalController; +    private final AccessPointController mAccessPoints; +    private final MobileDataControllerImpl mMobileDataController;      // bluetooth      private boolean mBluetoothTethered = false; -    private int mBluetoothTetherIconId = -        com.android.internal.R.drawable.stat_sys_tether_bluetooth; - -    //wimax -    private boolean mWimaxSupported = false; -    private boolean mIsWimaxEnabled = false; -    private boolean mWimaxConnected = false; -    private boolean mWimaxIdle = false; -    private int mWimaxIconId = 0; -    private int mWimaxSignal = 0; -    private int mWimaxState = 0; -    private int mWimaxExtraState = 0;      // data connectivity (regardless of state, can we access the internet?)      // state of inet connection - 0 not connected, 100 connected      private boolean mConnected = false;      private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;      private String mConnectedNetworkTypeName; -    private int mLastConnectedNetworkType = ConnectivityManager.TYPE_NONE; - -    private int mInetCondition = 0; -    private int mLastInetCondition = 0; -    private static final int INET_CONDITION_THRESHOLD = 50; +    private boolean mInetCondition; // Used for Logging and demo. +    // States that don't belong to a subcontroller.      private boolean mAirplaneMode = false; -    private boolean mLastAirplaneMode = true; -      private Locale mLocale = null; -    private Locale mLastLocale = null; - -    // our ui -    Context mContext; -    ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>(); -    ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>(); -    ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>(); -    ArrayList<StatusBarHeaderView> mEmergencyViews = new ArrayList<>(); -    ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>(); -    ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks = -            new ArrayList<NetworkSignalChangedCallback>(); -    int mLastPhoneSignalIconId = -1; -    int mLastDataDirectionIconId = -1; -    int mLastWifiIconId = -1; -    int mLastWimaxIconId = -1; -    int mLastCombinedSignalIconId = -1; -    int mLastDataTypeIconId = -1; -    String mLastCombinedLabel = ""; -    private boolean mHasMobileDataFeature; - -    boolean mDataAndWifiStacked = false; - -    public interface SignalCluster { -        void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription); -        void setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon, -                String contentDescription, String typeContentDescription, boolean isTypeIconWide); -        void setIsAirplaneMode(boolean is, int airplaneIcon); -    } - -    private final AccessPointController mAccessPoints; -    private final MobileDataController mMobileDataController; -    private final ConnectivityManager mConnectivityManager; +    // All the callbacks. +    private ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<EmergencyListener>(); +    private ArrayList<CarrierLabelListener> mCarrierListeners = +            new ArrayList<CarrierLabelListener>(); +    private ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>(); +    private ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks = +            new ArrayList<NetworkSignalChangedCallback>();      /**       * Construct this controller object and register for updates. @@ -180,70 +114,50 @@ public class NetworkControllerImpl extends BroadcastReceiver          this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),                  (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),                  (WifiManager) context.getSystemService(Context.WIFI_SERVICE), -                new AccessPointController(context), new MobileDataController(context)); +                Config.readConfig(context), new AccessPointControllerImpl(context), +                new MobileDataControllerImpl(context));          registerListeners();      }      @VisibleForTesting      NetworkControllerImpl(Context context, ConnectivityManager connectivityManager, -            TelephonyManager telephonyManager, WifiManager wifiManager, -            AccessPointController accessPointController, -            MobileDataController mobileDataController) { +            TelephonyManager telephonyManager, WifiManager wifiManager, Config config, +            AccessPointControllerImpl accessPointController, +            MobileDataControllerImpl mobileDataController) {          mContext = context; -        final Resources res = context.getResources();          mConnectivityManager = connectivityManager;          mHasMobileDataFeature =                  mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); -        mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData); -        mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G); -        mAlwaysShowCdmaRssi = res.getBoolean( -                com.android.internal.R.bool.config_alwaysUseCdmaRssi); - -        // set up the default wifi icon, used when no radios have ever appeared -        updateWifiIcons(); -        updateWimaxIcons(); -          // telephony          mPhone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); -        mHspaDataDistinguishable = mContext.getResources().getBoolean( -                R.bool.config_hspa_data_distinguishable); -        mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator); -        mNetworkNameDefault = mContext.getString( -                com.android.internal.R.string.lockscreen_carrier_default); -        mNetworkName = mNetworkNameDefault;          // wifi          mWifiManager = wifiManager; -        Handler handler = new WifiHandler(); -        mWifiChannel = new AsyncChannel(); -        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger(); -        if (wifiMessenger != null) { -            mWifiChannel.connect(mContext, handler, wifiMessenger); -        } - -        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it -        updateAirplaneMode(); -        mLastLocale = mContext.getResources().getConfiguration().locale; +        mLocale = mContext.getResources().getConfiguration().locale;          mAccessPoints = accessPointController;          mMobileDataController = mobileDataController; -        mMobileDataController.setCallback(new MobileDataController.Callback() { +        mMobileDataController.setNetworkController(this); +        // TODO: Find a way to move this into MobileDataController. +        mMobileDataController.setCallback(new MobileDataControllerImpl.Callback() {              @Override              public void onMobileDataEnabled(boolean enabled) {                  notifyMobileDataEnabled(enabled);              }          }); +        mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature, +                mSignalsChangedCallbacks, mSignalClusters, this); +        mMobileSignalController = new MobileSignalController(mContext, config, +                mHasMobileDataFeature, mPhone, mSignalsChangedCallbacks, mSignalClusters, this); + +        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it +        updateAirplaneMode(true);      }      private void registerListeners() { -        mPhone.listen(mPhoneStateListener, -                          PhoneStateListener.LISTEN_SERVICE_STATE -                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS -                        | PhoneStateListener.LISTEN_CALL_STATE -                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE -                        | PhoneStateListener.LISTEN_DATA_ACTIVITY); +        mMobileSignalController.registerListener();          // broadcasts          IntentFilter filter = new IntentFilter(); @@ -256,29 +170,38 @@ public class NetworkControllerImpl extends BroadcastReceiver          filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);          filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);          filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); -        mWimaxSupported = mContext.getResources().getBoolean( -                com.android.internal.R.bool.config_wimaxEnabled); -        if(mWimaxSupported) { -            filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION); -            filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION); -            filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION); -        }          mContext.registerReceiver(this, filter);      } +    private void unregisterListeners() { +        mMobileSignalController.unregisterListener(); +        mContext.unregisterReceiver(this); +    } +      @Override -    public boolean canConfigWifi() { -        return mAccessPoints.canConfigWifi(); +    public AccessPointController getAccessPointController() { +        return mAccessPoints;      }      @Override -    public void onUserSwitched(int newUserId) { -        mAccessPoints.onUserSwitched(newUserId); +    public MobileDataController getMobileDataController() { +        return mMobileDataController; +    } + +    public void addEmergencyListener(EmergencyListener listener) { +        mEmergencyListeners.add(listener); +        refreshCarrierLabel(); +    } + +    public void addCarrierLabel(CarrierLabelListener listener) { +        mCarrierListeners.add(listener); +        refreshCarrierLabel();      }      private void notifyMobileDataEnabled(boolean enabled) { -        for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) { -            cb.onMobileDataEnabled(enabled); +        int length = mSignalsChangedCallbacks.size(); +        for (int i = 0; i < length; i++) { +            mSignalsChangedCallbacks.get(i).onMobileDataEnabled(enabled);          }      } @@ -290,34 +213,40 @@ public class NetworkControllerImpl extends BroadcastReceiver          return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;      } -    public boolean isEmergencyOnly() { -        return (mServiceState != null && mServiceState.isEmergencyOnly()); -    } - -    public void addCombinedLabelView(TextView v) { -        mCombinedLabelViews.add(v); +    public String getMobileNetworkName() { +        return mMobileSignalController.mCurrentState.networkName;      } -    public void addMobileLabelView(TextView v) { -        mMobileLabelViews.add(v); +    public boolean isEmergencyOnly() { +        return mMobileSignalController.isEmergencyOnly();      } -    public void addWifiLabelView(TextView v) { -        mWifiLabelViews.add(v); -    } +    /** +     * Emergency status may have changed (triggered by MobileSignalController), +     * so we should recheck and send out the state to listeners. +     */ +    void recalculateEmergency() { +        final boolean emergencyOnly = isEmergencyOnly(); -    public void addEmergencyLabelView(StatusBarHeaderView v) { -        mEmergencyViews.add(v); +        int length = mEmergencyListeners.size(); +        for (int i = 0; i < length; i++) { +            mEmergencyListeners.get(i).setEmergencyCallsOnly(emergencyOnly); +        }      }      public void addSignalCluster(SignalCluster cluster) {          mSignalClusters.add(cluster); -        refreshSignalCluster(cluster); +        cluster.setIsAirplaneMode(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON, +                R.string.accessibility_airplane_mode); +        mWifiSignalController.notifyListeners(); +        mMobileSignalController.notifyListeners();      }      public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {          mSignalsChangedCallbacks.add(cb); -        notifySignalsChangedCallbacks(cb); +        cb.onAirplaneModeChanged(mAirplaneMode); +        mWifiSignalController.notifyListeners(); +        mMobileSignalController.notifyListeners();      }      public void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) { @@ -325,26 +254,6 @@ public class NetworkControllerImpl extends BroadcastReceiver      }      @Override -    public void addAccessPointCallback(AccessPointCallback callback) { -        mAccessPoints.addCallback(callback); -    } - -    @Override -    public void removeAccessPointCallback(AccessPointCallback callback) { -        mAccessPoints.removeCallback(callback); -    } - -    @Override -    public void scanForAccessPoints() { -        mAccessPoints.scan(); -    } - -    @Override -    public boolean connect(AccessPoint ap) { -        return mAccessPoints.connect(ap); -    } - -    @Override      public void setWifiEnabled(final boolean enabled) {          new AsyncTask<Void, Void, Void>() {              @Override @@ -352,7 +261,7 @@ public class NetworkControllerImpl extends BroadcastReceiver                  // Disable tethering if enabling Wifi                  final int wifiApState = mWifiManager.getWifiApState();                  if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) || -                               (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) { +                        (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {                      mWifiManager.setWifiApEnabled(null, false);                  } @@ -363,1275 +272,1250 @@ public class NetworkControllerImpl extends BroadcastReceiver      }      @Override -    public DataUsageInfo getDataUsageInfo() { -        final DataUsageInfo info =  mMobileDataController.getDataUsageInfo(); -        if (info != null) { -            info.carrier = mNetworkName; +    public void onReceive(Context context, Intent intent) { +        if (CHATTY) { +            Log.d(TAG, "onReceive: intent=" + intent);          } -        return info; +        final String action = intent.getAction(); +        if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE) || +                action.equals(ConnectivityManager.INET_CONDITION_ACTION)) { +            updateConnectivity(intent); +            refreshCarrierLabel(); +        } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { +            refreshLocale(); +            refreshCarrierLabel(); +        } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { +            refreshLocale(); +            updateAirplaneMode(false); +            refreshCarrierLabel(); +        } +        mWifiSignalController.handleBroadcast(intent); +        mMobileSignalController.handleBroadcast(intent);      } -    @Override -    public boolean isMobileDataSupported() { -        return mMobileDataController.isMobileDataSupported(); +    private void updateAirplaneMode(boolean force) { +        boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(), +                Settings.Global.AIRPLANE_MODE_ON, 0) == 1); +        if (airplaneMode != mAirplaneMode || force) { +            mAirplaneMode = airplaneMode; +            mMobileSignalController.setAirplaneMode(mAirplaneMode); +            notifyAirplaneCallbacks(); +            refreshCarrierLabel(); +        }      } -    @Override -    public boolean isMobileDataEnabled() { -        return mMobileDataController.isMobileDataEnabled(); +    private void refreshLocale() { +        Locale current = mContext.getResources().getConfiguration().locale; +        if (current.equals(mLocale)) { +            mLocale = current; +            notifyAllListeners(); +        }      } -    @Override -    public void setMobileDataEnabled(boolean enabled) { -        mMobileDataController.setMobileDataEnabled(enabled); +    /** +     * Turns inet condition into a boolean indexing for a specific network. +     * returns 0 for bad connectivity on this network. +     * returns 1 for good connectivity on this network. +     */ +    private int inetConditionForNetwork(int networkType, boolean inetCondition) { +        return (inetCondition && mConnectedNetworkType == networkType) ? 1 : 0;      } -    private boolean isTypeIconWide(int iconId) { -        return TelephonyIcons.ICON_LTE == iconId || TelephonyIcons.ICON_1X == iconId -                || TelephonyIcons.ICON_3G == iconId || TelephonyIcons.ICON_4G == iconId; +    private void notifyAllListeners() { +        // Something changed, trigger everything! +        notifyAirplaneCallbacks(); +        mMobileSignalController.notifyListeners(); +        mWifiSignalController.notifyListeners();      } -    private boolean isQsTypeIconWide(int iconId) { -        return TelephonyIcons.QS_ICON_LTE == iconId || TelephonyIcons.QS_ICON_1X == iconId -                || TelephonyIcons.QS_ICON_3G == iconId || TelephonyIcons.QS_ICON_4G == iconId; +    private void notifyAirplaneCallbacks() { +        int length = mSignalClusters.size(); +        for (int i = 0; i < length; i++) { +            mSignalClusters.get(i).setIsAirplaneMode(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON, +                    R.string.accessibility_airplane_mode); +        } +        // update QS +        int signalsChangedLength = mSignalsChangedCallbacks.size(); +        for (int i = 0; i < signalsChangedLength; i++) { +            mSignalsChangedCallbacks.get(i).onAirplaneModeChanged(mAirplaneMode); +        }      } -    public void refreshSignalCluster(SignalCluster cluster) { -        if (mDemoMode) return; -        cluster.setWifiIndicators( -                // only show wifi in the cluster if connected or if wifi-only -                mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature), -                mWifiIconId, -                mContentDescriptionWifi); - -        if (mIsWimaxEnabled && mWimaxConnected) { -            // wimax is special -            cluster.setMobileDataIndicators( -                    true, -                    mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId, -                    mDataTypeIconId, -                    mContentDescriptionWimax, -                    mContentDescriptionDataType, -                    false /* isTypeIconWide */ ); -        } else { -            // normal mobile data -            cluster.setMobileDataIndicators( -                    mHasMobileDataFeature, -                    mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId, -                    mDataTypeIconId, -                    mContentDescriptionPhoneSignal, -                    mContentDescriptionDataType, -                    isTypeIconWide(mDataTypeIconId)); -        } -        cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId); -    } +    /** +     * Update the Inet conditions and what network we are connected to. +     */ +    private void updateConnectivity(Intent intent) { +        final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); -    void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) { -        // only show wifi in the cluster if connected or if wifi-only -        boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature); -        String wifiDesc = wifiEnabled ? -                mWifiSsid : null; -        boolean wifiIn = wifiEnabled && mWifiSsid != null -                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT -                || mWifiActivity == WifiManager.DATA_ACTIVITY_IN); -        boolean wifiOut = wifiEnabled && mWifiSsid != null -                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT -                || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT); -        cb.onWifiSignalChanged(mWifiEnabled, mWifiConnected, mQSWifiIconId, wifiIn, wifiOut, -                mContentDescriptionWifi, wifiDesc); - -        boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT -                || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN); -        boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT -                || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT); -        if (isEmergencyOnly()) { -            cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId, -                    mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut, -                    mContentDescriptionDataType, null, mNoSim, isQsTypeIconWide(mQSDataTypeIconId)); +        // Are we connected at all, by any interface? +        mConnected = info != null && info.isConnected(); +        if (mConnected) { +            mConnectedNetworkType = info.getType(); +            mConnectedNetworkTypeName = info.getTypeName();          } else { -            if (mIsWimaxEnabled && mWimaxConnected) { -                // Wimax is special -                cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId, -                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut, -                        mContentDescriptionDataType, mNetworkName, mNoSim, -                        isQsTypeIconWide(mQSDataTypeIconId)); -            } else { -                // Normal mobile data -                cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId, -                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut, -                        mContentDescriptionDataType, mNetworkName, mNoSim, -                        isQsTypeIconWide(mQSDataTypeIconId)); -            } +            mConnectedNetworkType = ConnectivityManager.TYPE_NONE; +            mConnectedNetworkTypeName = null;          } -        cb.onAirplaneModeChanged(mAirplaneMode); -    } -    public void setStackedMode(boolean stacked) { -        mDataAndWifiStacked = true; -    } +        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0); -    @Override -    public void onReceive(Context context, Intent intent) { -        final String action = intent.getAction(); -        if (action.equals(WifiManager.RSSI_CHANGED_ACTION) -                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) -                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { -            updateWifiState(intent); -            refreshViews(); -        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { -            updateSimState(intent); -            updateDataIcon(); -            refreshViews(); -        } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) { -            updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false), -                        intent.getStringExtra(TelephonyIntents.EXTRA_SPN), -                        intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false), -                        intent.getStringExtra(TelephonyIntents.EXTRA_PLMN)); -            refreshViews(); -        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE) || -                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) { -            updateConnectivity(intent); -            refreshViews(); -        } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { -            refreshLocale(); -            refreshViews(); -        } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { -            refreshLocale(); -            updateAirplaneMode(); -            refreshViews(); -        } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) || -                action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) || -                action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) { -            updateWimaxState(intent); -            refreshViews(); +        if (CHATTY) { +            Log.d(TAG, "updateConnectivity: networkInfo=" + info); +            Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);          } + +        mInetCondition = connectionStatus > INET_CONDITION_THRESHOLD; + +        if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) { +            mBluetoothTethered = info.isConnected(); +        } else { +            mBluetoothTethered = false; +        } + +        // We want to update all the icons, all at once, for any condition change +        mMobileSignalController.setInetCondition(mInetCondition ? 1 : 0, +                inetConditionForNetwork(mMobileSignalController.getNetworkType(), mInetCondition)); +        mWifiSignalController.setInetCondition( +                inetConditionForNetwork(mWifiSignalController.getNetworkType(), mInetCondition));      } +    /** +     * Recalculate and update the carrier label. +     */ +    void refreshCarrierLabel() { +        Context context = mContext; -    // ===== Telephony ============================================================== +        WifiSignalController.WifiState wifiState = mWifiSignalController.getState(); +        MobileSignalController.MobileState mobileState = mMobileSignalController.getState(); +        String label = mMobileSignalController.getLabel("", mConnected, mHasMobileDataFeature); -    PhoneStateListener mPhoneStateListener = new PhoneStateListener() { -        @Override -        public void onSignalStrengthsChanged(SignalStrength signalStrength) { -            if (DEBUG) { -                Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength + -                    ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel()))); -            } -            mSignalStrength = signalStrength; -            updateTelephonySignalStrength(); -            refreshViews(); +        // TODO Simplify this ugliness, some of the flows below shouldn't be possible anymore +        // but stay for the sake of history. +        if (mBluetoothTethered && !mHasMobileDataFeature) { +            label = mContext.getString(R.string.bluetooth_tethered);          } -        @Override -        public void onServiceStateChanged(ServiceState state) { -            if (DEBUG) { -                Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState() -                        + " dataState=" + state.getDataRegState()); -            } -            mServiceState = state; -            updateTelephonySignalStrength(); -            updateDataNetType(); -            updateDataIcon(); -            refreshViews(); +        final boolean ethernetConnected = +                (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET); +        if (ethernetConnected && !mHasMobileDataFeature) { +            label = context.getString(R.string.ethernet_label);          } -        @Override -        public void onCallStateChanged(int state, String incomingNumber) { -            if (DEBUG) { -                Log.d(TAG, "onCallStateChanged state=" + state); -            } -            // In cdma, if a voice call is made, RSSI should switch to 1x. -            if (isCdma()) { -                updateTelephonySignalStrength(); -                refreshViews(); +        if (mAirplaneMode && (!mobileState.connected && !mobileState.isEmergency)) { +            // combined values from connected wifi take precedence over airplane mode +            if (wifiState.connected && mHasMobileDataFeature) { +                // Suppress "No internet connection." from mobile if wifi connected. +                label = ""; +            } else { +                 if (!mHasMobileDataFeature) { +                      label = context.getString( +                              R.string.status_bar_settings_signal_meter_disconnected); +                 }              } +        } else if (!mobileState.dataConnected && !wifiState.connected && !mBluetoothTethered && +                 !ethernetConnected && !mHasMobileDataFeature) { +            // Pretty much no connection. +            label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);          } -        @Override -        public void onDataConnectionStateChanged(int state, int networkType) { -            if (DEBUG) { -                Log.d(TAG, "onDataConnectionStateChanged: state=" + state -                        + " type=" + networkType); -            } -            mDataState = state; -            mDataNetType = networkType; -            updateDataNetType(); -            updateDataIcon(); -            refreshViews(); +        // for mobile devices, we always show mobile connection info here (SPN/PLMN) +        // for other devices, we show whatever network is connected +        // This is determined above by references to mHasMobileDataFeature. +        int length = mCarrierListeners.size(); +        for (int i = 0; i < length; i++) { +            mCarrierListeners.get(i).setCarrierLabel(label);          } +    } -        @Override -        public void onDataActivity(int direction) { -            if (DEBUG) { -                Log.d(TAG, "onDataActivity: direction=" + direction); -            } -            mDataActivity = direction; -            updateDataIcon(); -            refreshViews(); -        } -    }; +    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { +        pw.println("NetworkController state:"); +        pw.println(String.format("  %s network type %d (%s)", +                mConnected ? "CONNECTED" : "DISCONNECTED", +                mConnectedNetworkType, mConnectedNetworkTypeName)); +        pw.println("  - telephony ------"); +        pw.print("  hasVoiceCallingFeature()="); +        pw.println(hasVoiceCallingFeature()); -    private final void updateSimState(Intent intent) { -        String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); -        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { -            mSimState = IccCardConstants.State.ABSENT; -        } -        else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { -            mSimState = IccCardConstants.State.READY; -        } -        else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { -            final String lockedReason = -                    intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); -            if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { -                mSimState = IccCardConstants.State.PIN_REQUIRED; +        pw.println("  - Bluetooth ----"); +        pw.print("  mBtReverseTethered="); +        pw.println(mBluetoothTethered); + +        pw.println("  - connectivity ------"); +        pw.print("  mInetCondition="); +        pw.println(mInetCondition); +        pw.print("  mAirplaneMode="); +        pw.println(mAirplaneMode); +        pw.print("  mLocale="); +        pw.println(mLocale); + +        mMobileSignalController.dump(pw); +        mWifiSignalController.dump(pw); +    } + +    private boolean mDemoMode; +    private int mDemoInetCondition; +    private WifiSignalController.WifiState mDemoWifiState; +    private MobileSignalController.MobileState mDemoMobileState; + +    @Override +    public void dispatchDemoCommand(String command, Bundle args) { +        if (!mDemoMode && command.equals(COMMAND_ENTER)) { +            if (DEBUG) Log.d(TAG, "Entering demo mode"); +            unregisterListeners(); +            mDemoMode = true; +            mDemoInetCondition = mInetCondition ? 1 : 0; +            mDemoWifiState = mWifiSignalController.getState(); +            mDemoMobileState = mMobileSignalController.getState(); +        } else if (mDemoMode && command.equals(COMMAND_EXIT)) { +            if (DEBUG) Log.d(TAG, "Exiting demo mode"); +            mDemoMode = false; +            mWifiSignalController.resetLastState(); +            mMobileSignalController.resetLastState(); +            registerListeners(); +            notifyAllListeners(); +            refreshCarrierLabel(); +        } else if (mDemoMode && command.equals(COMMAND_NETWORK)) { +            String airplane = args.getString("airplane"); +            if (airplane != null) { +                boolean show = airplane.equals("show"); +                int length = mSignalClusters.size(); +                for (int i = 0; i < length; i++) { +                    mSignalClusters.get(i).setIsAirplaneMode(show, TelephonyIcons.FLIGHT_MODE_ICON, +                            R.string.accessibility_airplane_mode); +                }              } -            else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { -                mSimState = IccCardConstants.State.PUK_REQUIRED; +            String fully = args.getString("fully"); +            if (fully != null) { +                mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0; +                mWifiSignalController.setInetCondition(mDemoInetCondition); +                mMobileSignalController.setInetCondition(mDemoInetCondition, mDemoInetCondition); +            } +            String wifi = args.getString("wifi"); +            if (wifi != null) { +                boolean show = wifi.equals("show"); +                String level = args.getString("level"); +                if (level != null) { +                    mDemoWifiState.level = level.equals("null") ? -1 +                            : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1); +                    mDemoWifiState.connected = mDemoWifiState.level >= 0; +                } +                mDemoWifiState.enabled = show; +                mWifiSignalController.notifyListeners();              } -            else { -                mSimState = IccCardConstants.State.NETWORK_LOCKED; +            String mobile = args.getString("mobile"); +            if (mobile != null) { +                boolean show = mobile.equals("show"); +                String datatype = args.getString("datatype"); +                if (datatype != null) { +                    mDemoMobileState.iconGroup = +                            datatype.equals("1x") ? TelephonyIcons.ONE_X : +                            datatype.equals("3g") ? TelephonyIcons.THREE_G : +                            datatype.equals("4g") ? TelephonyIcons.FOUR_G : +                            datatype.equals("e") ? TelephonyIcons.E : +                            datatype.equals("g") ? TelephonyIcons.G : +                            datatype.equals("h") ? TelephonyIcons.H : +                            datatype.equals("lte") ? TelephonyIcons.LTE : +                            datatype.equals("roam") ? TelephonyIcons.ROAMING : +                            TelephonyIcons.UNKNOWN; +                } +                int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH; +                String level = args.getString("level"); +                if (level != null) { +                    mDemoMobileState.level = level.equals("null") ? -1 +                            : Math.min(Integer.parseInt(level), icons[0].length - 1); +                    mDemoMobileState.connected = mDemoMobileState.level >= 0; +                } +                mDemoMobileState.enabled = show; +                mMobileSignalController.notifyListeners();              } -        } else { -            mSimState = IccCardConstants.State.UNKNOWN; +            refreshCarrierLabel();          } -        if (DEBUG) Log.d(TAG, "updateSimState: mSimState=" + mSimState); -    } - -    private boolean isCdma() { -        return (mSignalStrength != null) && !mSignalStrength.isGsm();      } -    private boolean hasService() { -        boolean retVal; -        if (mServiceState != null) { -            // Consider the device to be in service if either voice or data service is available. -            // Some SIM cards are marketed as data-only and do not support voice service, and on -            // these SIM cards, we want to show signal bars for data service as well as the "no -            // service" or "emergency calls only" text that indicates that voice is not available. -            switch(mServiceState.getVoiceRegState()) { -                case ServiceState.STATE_POWER_OFF: -                    retVal = false; -                    break; -                case ServiceState.STATE_OUT_OF_SERVICE: -                case ServiceState.STATE_EMERGENCY_ONLY: -                    retVal = mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; -                    break; -                default: -                    retVal = true; +    static class WifiSignalController extends +            SignalController<WifiSignalController.WifiState, SignalController.IconGroup> { +        private final WifiManager mWifiManager; +        private final AsyncChannel mWifiChannel; +        private final boolean mHasMobileData; + +        public WifiSignalController(Context context, boolean hasMobileData, +                List<NetworkSignalChangedCallback> signalCallbacks, +                List<SignalCluster> signalClusters, NetworkControllerImpl networkController) { +            super("WifiSignalController", context, ConnectivityManager.TYPE_WIFI, signalCallbacks, +                    signalClusters, networkController); +            mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); +            mHasMobileData = hasMobileData; +            Handler handler = new WifiHandler(); +            mWifiChannel = new AsyncChannel(); +            Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger(); +            if (wifiMessenger != null) { +                mWifiChannel.connect(context, handler, wifiMessenger);              } -        } else { -            retVal = false; +            // WiFi only has one state. +            mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup( +                    "Wi-Fi Icons", +                    WifiIcons.WIFI_SIGNAL_STRENGTH, +                    WifiIcons.QS_WIFI_SIGNAL_STRENGTH, +                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH, +                    WifiIcons.WIFI_NO_NETWORK, +                    WifiIcons.QS_WIFI_NO_NETWORK, +                    WifiIcons.WIFI_NO_NETWORK, +                    WifiIcons.QS_WIFI_NO_NETWORK, +                    AccessibilityContentDescriptions.WIFI_NO_CONNECTION +                    );          } -        if (DEBUG) Log.d(TAG, "hasService: mServiceState=" + mServiceState + " retVal=" + retVal); -        return retVal; -    } - -    private void updateAirplaneMode() { -        mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(), -            Settings.Global.AIRPLANE_MODE_ON, 0) == 1); -    } -    private void refreshLocale() { -        mLocale = mContext.getResources().getConfiguration().locale; -    } +        @Override +        public WifiState cleanState() { +            return new WifiState(); +        } -    private final void updateTelephonySignalStrength() { -        if (DEBUG) { -            Log.d(TAG, "updateTelephonySignalStrength: hasService=" + hasService() -                    + " ss=" + mSignalStrength); -        } -        if (!hasService()) { -            if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()"); -            mPhoneSignalIconId = R.drawable.stat_sys_signal_null; -            mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal; -            mDataSignalIconId = R.drawable.stat_sys_signal_null; -            mContentDescriptionPhoneSignal = mContext.getString( -                    AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]); -        } else { -            if (mSignalStrength == null) { -                if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null"); -                mPhoneSignalIconId = R.drawable.stat_sys_signal_null; -                mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal; -                mDataSignalIconId = R.drawable.stat_sys_signal_null; -                mContentDescriptionPhoneSignal = mContext.getString( -                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]); -            } else { -                int iconLevel; -                int[] iconList; -                if (isCdma() && mAlwaysShowCdmaRssi) { -                    mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel(); -                    if (DEBUG) { -                        Log.d(TAG, "updateTelephonySignalStrength:" -                            + " mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi -                            + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel() -                            + " instead of level=" + mSignalStrength.getLevel()); -                    } -                } else { -                    mLastSignalLevel = iconLevel = mSignalStrength.getLevel(); -                } +        /** +         * {@inheritDoc} +         */ +        @Override +        public void notifyListeners() { +            // only show wifi in the cluster if connected or if wifi-only +            boolean wifiEnabled = mCurrentState.enabled +                    && (mCurrentState.connected || !mHasMobileData); +            String wifiDesc = wifiEnabled ? mCurrentState.ssid : null; +            boolean ssidPresent = wifiEnabled && mCurrentState.ssid != null; +            String contentDescription = getStringIfExists(getContentDescription()); +            int length = mSignalsChangedCallbacks.size(); +            for (int i = 0; i < length; i++) { +                mSignalsChangedCallbacks.get(i).onWifiSignalChanged(mCurrentState.enabled, +                        mCurrentState.connected, getQsCurrentIconId(), +                        ssidPresent && mCurrentState.activityIn, +                        ssidPresent && mCurrentState.activityOut, contentDescription, wifiDesc); +            } -                if (isRoaming()) { -                    iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition]; -                } else { -                    iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition]; -                } -                mPhoneSignalIconId = iconList[iconLevel]; -                mQSPhoneSignalIconId = -                        TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel]; -                mContentDescriptionPhoneSignal = mContext.getString( -                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]); -                mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel]; -                if (DEBUG) Log.d(TAG, "updateTelephonySignalStrength: iconLevel=" + iconLevel); +            int signalClustersLength = mSignalClusters.size(); +            for (int i = 0; i < signalClustersLength; i++) { +                mSignalClusters.get(i).setWifiIndicators( +                        // only show wifi in the cluster if connected or if wifi-only +                        mCurrentState.enabled && (mCurrentState.connected || !mHasMobileData), +                        getCurrentIconId(), contentDescription);              }          } -    } - -    private int inetConditionForNetwork(int networkType) { -        return (mInetCondition == 1 && mConnectedNetworkType == networkType) ? 1 : 0; -    } -    private final void updateDataNetType() { -        int inetCondition; -        mDataTypeIconId = mQSDataTypeIconId = 0; -        if (mIsWimaxEnabled && mWimaxConnected) { -            // wimax is a special 4g network not handled by telephony -            inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_WIMAX); -            mDataIconList = TelephonyIcons.DATA_4G[inetCondition]; -            mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g; -            mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[inetCondition]; -            mContentDescriptionDataType = mContext.getString( -                    R.string.accessibility_data_connection_4g); -        } else { -            inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_MOBILE); -            final boolean showDataTypeIcon = (inetCondition > 0); -            switch (mDataNetType) { -                case TelephonyManager.NETWORK_TYPE_UNKNOWN: -                    if (!mShowAtLeastThreeGees) { -                        mDataIconList = TelephonyIcons.DATA_G[inetCondition]; -                        mContentDescriptionDataType = ""; -                        break; -                    } else { -                        // fall through -                    } -                case TelephonyManager.NETWORK_TYPE_EDGE: -                    if (!mShowAtLeastThreeGees) { -                        mDataIconList = TelephonyIcons.DATA_E[inetCondition]; -                        mDataTypeIconId = showDataTypeIcon ? -                                R.drawable.stat_sys_data_fully_connected_e : 0; -                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[inetCondition]; -                        mContentDescriptionDataType = mContext.getString( -                                R.string.accessibility_data_connection_edge); -                        break; -                    } else { -                        // fall through -                    } -                case TelephonyManager.NETWORK_TYPE_UMTS: -                    mDataIconList = TelephonyIcons.DATA_3G[inetCondition]; -                    mDataTypeIconId = showDataTypeIcon ? -                                R.drawable.stat_sys_data_fully_connected_3g : 0; -                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition]; -                    mContentDescriptionDataType = mContext.getString( -                            R.string.accessibility_data_connection_3g); -                    break; -                case TelephonyManager.NETWORK_TYPE_HSDPA: -                case TelephonyManager.NETWORK_TYPE_HSUPA: -                case TelephonyManager.NETWORK_TYPE_HSPA: -                case TelephonyManager.NETWORK_TYPE_HSPAP: -                    if (mHspaDataDistinguishable) { -                        mDataIconList = TelephonyIcons.DATA_H[inetCondition]; -                        mDataTypeIconId = showDataTypeIcon ? -                                R.drawable.stat_sys_data_fully_connected_h : 0; -                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[inetCondition]; -                        mContentDescriptionDataType = mContext.getString( -                                R.string.accessibility_data_connection_3_5g); +        /** +         * Extract wifi state directly from broadcasts about changes in wifi state. +         */ +        public void handleBroadcast(Intent intent) { +            String action = intent.getAction(); +            if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { +                mCurrentState.enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, +                        WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; +            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { +                final NetworkInfo networkInfo = (NetworkInfo) +                        intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); +                mCurrentState.connected = networkInfo != null && networkInfo.isConnected(); +                // If Connected grab the signal strength and ssid. +                if (mCurrentState.connected) { +                    // try getting it out of the intent first +                    WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null +                            ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) +                            : mWifiManager.getConnectionInfo(); +                    if (info != null) { +                        mCurrentState.ssid = huntForSsid(info);                      } else { -                        mDataIconList = TelephonyIcons.DATA_3G[inetCondition]; -                        mDataTypeIconId = showDataTypeIcon ? -                                R.drawable.stat_sys_data_fully_connected_3g : 0; -                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition]; -                        mContentDescriptionDataType = mContext.getString( -                                R.string.accessibility_data_connection_3g); +                        mCurrentState.ssid = null;                      } -                    break; -                case TelephonyManager.NETWORK_TYPE_CDMA: -                    if (!mShowAtLeastThreeGees) { -                        // display 1xRTT for IS95A/B -                        mDataIconList = TelephonyIcons.DATA_1X[inetCondition]; -                        mDataTypeIconId = showDataTypeIcon ? -                                R.drawable.stat_sys_data_fully_connected_1x : 0; -                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[inetCondition]; -                        mContentDescriptionDataType = mContext.getString( -                                R.string.accessibility_data_connection_cdma); -                        break; -                    } else { -                        // fall through -                    } -                case TelephonyManager.NETWORK_TYPE_1xRTT: -                    if (!mShowAtLeastThreeGees) { -                        mDataIconList = TelephonyIcons.DATA_1X[inetCondition]; -                        mDataTypeIconId = showDataTypeIcon ? -                                R.drawable.stat_sys_data_fully_connected_1x : 0; -                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[inetCondition]; -                        mContentDescriptionDataType = mContext.getString( -                                R.string.accessibility_data_connection_cdma); -                        break; -                    } else { -                        // fall through -                    } -                case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through -                case TelephonyManager.NETWORK_TYPE_EVDO_A: -                case TelephonyManager.NETWORK_TYPE_EVDO_B: -                case TelephonyManager.NETWORK_TYPE_EHRPD: -                    mDataIconList = TelephonyIcons.DATA_3G[inetCondition]; -                    mDataTypeIconId = showDataTypeIcon ? -                                R.drawable.stat_sys_data_fully_connected_3g : 0; -                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition]; -                    mContentDescriptionDataType = mContext.getString( -                            R.string.accessibility_data_connection_3g); -                    break; -                case TelephonyManager.NETWORK_TYPE_LTE: -                    boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE); -                    if (show4GforLTE) { -                        mDataIconList = TelephonyIcons.DATA_4G[inetCondition]; -                        mDataTypeIconId = showDataTypeIcon ? -                                R.drawable.stat_sys_data_fully_connected_4g : 0; -                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[inetCondition]; -                        mContentDescriptionDataType = mContext.getString( -                                R.string.accessibility_data_connection_4g); -                    } else { -                        mDataIconList = TelephonyIcons.DATA_LTE[inetCondition]; -                        mDataTypeIconId = showDataTypeIcon ? TelephonyIcons.ICON_LTE : 0; -                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[inetCondition]; -                        mContentDescriptionDataType = mContext.getString( -                                R.string.accessibility_data_connection_lte); -                    } -                    break; -                default: -                    if (!mShowAtLeastThreeGees) { -                        mDataIconList = TelephonyIcons.DATA_G[inetCondition]; -                        mDataTypeIconId = showDataTypeIcon ? -                                R.drawable.stat_sys_data_fully_connected_g : 0; -                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[inetCondition]; -                        mContentDescriptionDataType = mContext.getString( -                                R.string.accessibility_data_connection_gprs); -                    } else { -                        mDataIconList = TelephonyIcons.DATA_3G[inetCondition]; -                        mDataTypeIconId = showDataTypeIcon ? -                                R.drawable.stat_sys_data_fully_connected_3g : 0; -                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition]; -                        mContentDescriptionDataType = mContext.getString( -                                R.string.accessibility_data_connection_3g); -                    } -                    break; +                } else if (!mCurrentState.connected) { +                    mCurrentState.ssid = null; +                } +            } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { +                mCurrentState.rssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); +                mCurrentState.level = WifiManager.calculateSignalLevel( +                        mCurrentState.rssi, WifiIcons.WIFI_LEVEL_COUNT);              } -        } -        if (isRoaming()) { -            mDataTypeIconId = TelephonyIcons.ROAMING_ICON; -            mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition]; +            notifyListenersIfNecessary();          } -    } -    boolean isCdmaEri() { -        if (mServiceState != null) { -            final int iconIndex = mServiceState.getCdmaEriIconIndex(); -            if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) { -                final int iconMode = mServiceState.getCdmaEriIconMode(); -                if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL -                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) { -                    return true; +        private String huntForSsid(WifiInfo info) { +            String ssid = info.getSSID(); +            if (ssid != null) { +                return ssid; +            } +            // OK, it's not in the connectionInfo; we have to go hunting for it +            List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks(); +            int length = networks.size(); +            for (int i = 0; i < length; i++) { +                if (networks.get(i).networkId == info.getNetworkId()) { +                    return networks.get(i).SSID;                  }              } +            return null;          } -        return false; -    } -    private boolean isRoaming() { -        if (isCdma()) { -            return isCdmaEri(); -        } else { -            return mServiceState != null && mServiceState.getRoaming(); +        @VisibleForTesting +        void setActivity(int wifiActivity) { +            mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT +                    || wifiActivity == WifiManager.DATA_ACTIVITY_IN; +            mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT +                    || wifiActivity == WifiManager.DATA_ACTIVITY_OUT; +            notifyListenersIfNecessary();          } -    } -    private final void updateDataIcon() { -        int iconId; -        boolean visible = true; - -        if (!isCdma()) { -            // GSM case, we have to check also the sim state -            if (mSimState == IccCardConstants.State.READY || -                    mSimState == IccCardConstants.State.UNKNOWN) { -                mNoSim = false; -                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { -                    switch (mDataActivity) { -                        case TelephonyManager.DATA_ACTIVITY_IN: -                            iconId = mDataIconList[1]; -                            break; -                        case TelephonyManager.DATA_ACTIVITY_OUT: -                            iconId = mDataIconList[2]; -                            break; -                        case TelephonyManager.DATA_ACTIVITY_INOUT: -                            iconId = mDataIconList[3]; -                            break; -                        default: -                            iconId = mDataIconList[0]; -                            break; -                    } -                    mDataDirectionIconId = iconId; -                } else { -                    iconId = 0; -                    visible = false; -                } -            } else { -                iconId = 0; -                mNoSim = true; -                visible = false; // no SIM? no data -            } -        } else { -            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT -            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { -                switch (mDataActivity) { -                    case TelephonyManager.DATA_ACTIVITY_IN: -                        iconId = mDataIconList[1]; -                        break; -                    case TelephonyManager.DATA_ACTIVITY_OUT: -                        iconId = mDataIconList[2]; +        /** +         * Handler to receive the data activity on wifi. +         */ +        class WifiHandler extends Handler { +            @Override +            public void handleMessage(Message msg) { +                switch (msg.what) { +                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: +                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { +                            mWifiChannel.sendMessage(Message.obtain(this, +                                    AsyncChannel.CMD_CHANNEL_FULL_CONNECTION)); +                        } else { +                            Log.e(mTag, "Failed to connect to wifi"); +                        }                          break; -                    case TelephonyManager.DATA_ACTIVITY_INOUT: -                        iconId = mDataIconList[3]; +                    case WifiManager.DATA_ACTIVITY_NOTIFICATION: +                        setActivity(msg.arg1);                          break; -                    case TelephonyManager.DATA_ACTIVITY_DORMANT:                      default: -                        iconId = mDataIconList[0]; +                        // Ignore                          break;                  } -            } else { -                iconId = 0; -                visible = false;              }          } -        mDataDirectionIconId = iconId; -        mDataConnected = visible; -    } +        static class WifiState extends SignalController.State { +            String ssid; -    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) { -        if (false) { -            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn -                    + " showPlmn=" + showPlmn + " plmn=" + plmn); -        } -        StringBuilder str = new StringBuilder(); -        boolean something = false; -        if (showPlmn && plmn != null) { -            str.append(plmn); -            something = true; -        } -        if (showSpn && spn != null) { -            if (something) { -                str.append(mNetworkNameSeparator); +            @Override +            public void copyFrom(State s) { +                WifiState state = (WifiState) s; +                ssid = state.ssid; +                super.copyFrom(s);              } -            str.append(spn); -            something = true; -        } -        if (something) { -            mNetworkName = str.toString(); -        } else { -            mNetworkName = mNetworkNameDefault; -        } -    } -    // ===== Wifi =================================================================== +            @Override +            protected void toString(StringBuilder builder) { +                builder.append("ssid=").append(ssid).append(','); +                super.toString(builder); +            } -    class WifiHandler extends Handler { -        @Override -        public void handleMessage(Message msg) { -            switch (msg.what) { -                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: -                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { -                        mWifiChannel.sendMessage(Message.obtain(this, -                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION)); -                    } else { -                        Log.e(TAG, "Failed to connect to wifi"); -                    } -                    break; -                case WifiManager.DATA_ACTIVITY_NOTIFICATION: -                    if (msg.arg1 != mWifiActivity) { -                        mWifiActivity = msg.arg1; -                        refreshViews(); -                    } -                    break; -                default: -                    //Ignore -                    break; +            @Override +            public boolean equals(Object o) { +                return super.equals(o) +                        && Objects.equals(((WifiState) o).ssid, ssid);              }          }      } -    private void updateWifiState(Intent intent) { -        final String action = intent.getAction(); -        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { -            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; - -        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { -            final NetworkInfo networkInfo = (NetworkInfo) -                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); -            boolean wasConnected = mWifiConnected; -            mWifiConnected = networkInfo != null && networkInfo.isConnected(); -            // If Connected grab the signal strength and ssid -            if (mWifiConnected) { -                // try getting it out of the intent first -                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO); -                if (info == null) { -                    info = mWifiManager.getConnectionInfo(); +    static class MobileSignalController extends SignalController<MobileSignalController.MobileState, +            MobileSignalController.MobileIconGroup> { +        private final Config mConfig; +        private final TelephonyManager mPhone; +        private final String mNetworkNameDefault; +        private final String mNetworkNameSeparator; + +        // @VisibleForDemoMode +        Map<Integer, MobileIconGroup> mNetworkToIconLookup; + +        // Since some pieces of the phone state are interdependent we store it locally, +        // this could potentially become part of MobileState for simplification/complication +        // of code. +        private IccCardConstants.State mSimState = IccCardConstants.State.READY; +        private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN; +        private int mDataState = TelephonyManager.DATA_DISCONNECTED; +        private ServiceState mServiceState; +        private SignalStrength mSignalStrength; +        private MobileIconGroup mDefaultIcons; + +        // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't +        // need listener lists anymore. +        public MobileSignalController(Context context, Config config, boolean hasMobileData, +                TelephonyManager phone, List<NetworkSignalChangedCallback> signalCallbacks, +                List<SignalCluster> signalClusters, NetworkControllerImpl networkController) { +            super("MobileSignalController", context, ConnectivityManager.TYPE_MOBILE, +                    signalCallbacks, signalClusters, networkController); +            mConfig = config; +            mPhone = phone; +            mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator); +            mNetworkNameDefault = getStringIfExists( +                    com.android.internal.R.string.lockscreen_carrier_default); + +            mapIconSets(); + +            mLastState.networkName = mCurrentState.networkName = mNetworkNameDefault; +            mLastState.enabled = mCurrentState.enabled = hasMobileData; +            mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons; +        } + +        /** +         * Get (the mobile parts of) the carrier string. +         * +         * @param currentLabel can be used for concatenation, currently just empty +         * @param connected whether the device has connection to the internet at all +         * @param isMobileLabel whether to always return the network or just when data is connected +         */ +        public String getLabel(String currentLabel, boolean connected, boolean isMobileLabel) { +            if (!mCurrentState.enabled) { +                return ""; +            } else { +                String mobileLabel = ""; +                // We want to show the carrier name if in service and either: +                // - We are connected to mobile data, or +                // - We are not connected to mobile data, as long as the *reason* packets are not +                //   being routed over that link is that we have better connectivity via wifi. +                // If data is disconnected for some other reason but wifi (or ethernet/bluetooth) +                // is connected, we show nothing. +                // Otherwise (nothing connected) we show "No internet connection". +                if (mCurrentState.dataConnected) { +                    mobileLabel = mCurrentState.networkName; +                } else if (connected || mCurrentState.isEmergency) { +                    if (mCurrentState.connected || mCurrentState.isEmergency) { +                        // The isEmergencyOnly test covers the case of a phone with no SIM +                        mobileLabel = mCurrentState.networkName; +                    } +                } else { +                    mobileLabel = mContext +                            .getString(R.string.status_bar_settings_signal_meter_disconnected);                  } -                if (info != null) { -                    mWifiSsid = huntForSsid(info); + +                // Now for things that should only be shown when actually using mobile data. +                if (isMobileLabel) { +                    return mobileLabel;                  } else { -                    mWifiSsid = null; +                    return mCurrentState.dataConnected ? mobileLabel : currentLabel;                  } -            } else if (!mWifiConnected) { -                mWifiSsid = null;              } -        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { -            mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); -            mWifiLevel = WifiManager.calculateSignalLevel( -                    mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);          } -        updateWifiIcons(); -    } +        public int getDataContentDescription() { +            return getIcons().mDataContentDescription; +        } -    private void updateWifiIcons() { -        int inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_WIFI); -        if (mWifiConnected) { -            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[inetCondition][mWifiLevel]; -            mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[inetCondition][mWifiLevel]; -            mContentDescriptionWifi = mContext.getString( -                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]); -        } else { -            if (mDataAndWifiStacked) { -                mWifiIconId = 0; -                mQSWifiIconId = 0; -            } else { -                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0; -                mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0; -            } -            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi); +        public void setAirplaneMode(boolean airplaneMode) { +            mCurrentState.airplaneMode = airplaneMode; +            notifyListenersIfNecessary();          } -    } -    private String huntForSsid(WifiInfo info) { -        String ssid = info.getSSID(); -        if (ssid != null) { -            return ssid; +        public void setInetCondition(int inetCondition, int inetConditionForNetwork) { +            // For mobile data, use general inet condition for phone signal indexing, +            // and network specific for data indexing (I think this might be a bug, but +            // keeping for now). +            // TODO: Update with explanation of why. +            mCurrentState.inetForNetwork = inetConditionForNetwork; +            setInetCondition(inetCondition);          } -        // OK, it's not in the connectionInfo; we have to go hunting for it -        List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks(); -        for (WifiConfiguration net : networks) { -            if (net.networkId == info.getNetworkId()) { -                return net.SSID; -            } + +        /** +         * Start listening for phone state changes. +         */ +        public void registerListener() { +            mPhone.listen(mPhoneStateListener, +                    PhoneStateListener.LISTEN_SERVICE_STATE +                            | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS +                            | PhoneStateListener.LISTEN_CALL_STATE +                            | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE +                            | PhoneStateListener.LISTEN_DATA_ACTIVITY);          } -        return null; -    } +        /** +         * Stop listening for phone state changes. +         */ +        public void unregisterListener() { +            mPhone.listen(mPhoneStateListener, 0); +        } -    // ===== Wimax =================================================================== -    private final void updateWimaxState(Intent intent) { -        final String action = intent.getAction(); -        boolean wasConnected = mWimaxConnected; -        if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) { -            int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE, -                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN); -            mIsWimaxEnabled = (wimaxStatus == -                    WimaxManagerConstants.NET_4G_STATE_ENABLED); -        } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) { -            mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0); -        } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) { -            mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE, -                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN); -            mWimaxExtraState = intent.getIntExtra( -                    WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL, -                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN); -            mWimaxConnected = (mWimaxState == -                    WimaxManagerConstants.WIMAX_STATE_CONNECTED); -            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE); -        } -        updateDataNetType(); -        updateWimaxIcons(); -    } +        /** +         * Produce a mapping of data network types to icon groups for simple and quick use in +         * updateTelephony. +         * +         * TODO: See if config can change with locale, this may need to be regenerated on Locale +         * change. +         */ +        private void mapIconSets() { +            mNetworkToIconLookup = new HashMap<Integer, MobileIconGroup>(); + +            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G); +            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G); +            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G); +            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G); +            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G); -    private void updateWimaxIcons() { -        if (mIsWimaxEnabled) { -            if (mWimaxConnected) { -                int inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_WIMAX); -                if (mWimaxIdle) -                    mWimaxIconId = WimaxIcons.WIMAX_IDLE; -                else -                    mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[inetCondition][mWimaxSignal]; -                mContentDescriptionWimax = mContext.getString( -                        AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]); +            if (!mConfig.showAtLeastThreeGees) { +                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN, +                        TelephonyIcons.UNKNOWN); +                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E); +                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X); +                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X); + +                mDefaultIcons = TelephonyIcons.G;              } else { -                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED; -                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax); +                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN, +                        TelephonyIcons.THREE_G); +                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, +                        TelephonyIcons.THREE_G); +                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, +                        TelephonyIcons.THREE_G); +                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, +                        TelephonyIcons.THREE_G); +                mDefaultIcons = TelephonyIcons.THREE_G;              } -        } else { -            mWimaxIconId = 0; -        } -    } -    // ===== Full or limited Internet connectivity ================================== +            MobileIconGroup hGroup = TelephonyIcons.THREE_G; +            if (mConfig.hspaDataDistinguishable) { +                hGroup = TelephonyIcons.H; +            } +            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup); +            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup); +            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup); +            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup); -    private void updateConnectivity(Intent intent) { -        if (CHATTY) { -            Log.d(TAG, "updateConnectivity: intent=" + intent); +            if (mConfig.show4gForLte) { +                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G); +            } else { +                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE); +            }          } -        final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); - -        // Are we connected at all, by any interface? -        mConnected = info != null && info.isConnected(); -        if (mConnected) { -            mConnectedNetworkType = info.getType(); -            mConnectedNetworkTypeName = info.getTypeName(); -        } else { -            mConnectedNetworkType = ConnectivityManager.TYPE_NONE; -            mConnectedNetworkTypeName = null; +        /** +         * {@inheritDoc} +         */ +        @Override +        public void notifyListeners() { +            MobileIconGroup icons = getIcons(); + +            String contentDescription = getStringIfExists(getContentDescription()); +            String dataContentDescription = getStringIfExists(icons.mDataContentDescription); +            int qsTypeIcon = icons.mQsDataType[mCurrentState.inetForNetwork]; +            int length = mSignalsChangedCallbacks.size(); +            for (int i = 0; i < length; i++) { +                mSignalsChangedCallbacks.get(i).onMobileDataSignalChanged(mCurrentState.enabled +                        && !mCurrentState.isEmergency && !mCurrentState.airplaneMode, +                        getQsCurrentIconId(), contentDescription, +                        qsTypeIcon, +                        mCurrentState.dataConnected && mCurrentState.activityIn, +                        mCurrentState.dataConnected && mCurrentState.activityOut, +                        dataContentDescription, +                        mCurrentState.isEmergency ? null : mCurrentState.networkName, +                        mCurrentState.noSim, +                        // Only wide if actually showing something. +                        icons.mIsWide && qsTypeIcon != 0); +            } +            boolean showDataIcon = mCurrentState.inetForNetwork != 0 +                    || mCurrentState.iconGroup == TelephonyIcons.ROAMING; +            int typeIcon = showDataIcon ? icons.mDataType : 0; +            int signalClustersLength = mSignalClusters.size(); +            for (int i = 0; i < signalClustersLength; i++) { +                mSignalClusters.get(i).setMobileDataIndicators( +                        mCurrentState.enabled && !mCurrentState.airplaneMode, +                        getCurrentIconId(), +                        typeIcon, +                        contentDescription, +                        dataContentDescription, +                        // Only wide if actually showing something. +                        icons.mIsWide && typeIcon != 0); +            }          } -        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0); - -        if (CHATTY) { -            Log.d(TAG, "updateConnectivity: networkInfo=" + info); -            Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus); +        @Override +        public MobileState cleanState() { +            return new MobileState(); +        } + +        private boolean hasService() { +            if (mServiceState != null) { +                // Consider the device to be in service if either voice or data +                // service is available. Some SIM cards are marketed as data-only +                // and do not support voice service, and on these SIM cards, we +                // want to show signal bars for data service as well as the "no +                // service" or "emergency calls only" text that indicates that voice +                // is not available. +                switch (mServiceState.getVoiceRegState()) { +                    case ServiceState.STATE_POWER_OFF: +                        return false; +                    case ServiceState.STATE_OUT_OF_SERVICE: +                    case ServiceState.STATE_EMERGENCY_ONLY: +                        return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; +                    default: +                        return true; +                } +            } else { +                return false; +            }          } -        mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0); - -        if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) { -            mBluetoothTethered = info.isConnected(); -        } else { -            mBluetoothTethered = false; +        private boolean isCdma() { +            return (mSignalStrength != null) && !mSignalStrength.isGsm();          } -        // We want to update all the icons, all at once, for any condition change -        updateDataNetType(); -        updateWimaxIcons(); -        updateDataIcon(); -        updateTelephonySignalStrength(); -        updateWifiIcons(); -    } - - -    // ===== Update the views ======================================================= +        public boolean isEmergencyOnly() { +            return (mServiceState != null && mServiceState.isEmergencyOnly()); +        } -    void refreshViews() { -        Context context = mContext; +        private boolean isRoaming() { +            if (isCdma()) { +                final int iconMode = mServiceState.getCdmaEriIconMode(); +                return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF +                        && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL +                            || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH); +            } else { +                return mServiceState != null && mServiceState.getRoaming(); +            } +        } -        int combinedSignalIconId = 0; -        String combinedLabel = ""; -        String wifiLabel = ""; -        String mobileLabel = ""; -        int N; -        final boolean emergencyOnly = isEmergencyOnly(); +        public void handleBroadcast(Intent intent) { +            String action = intent.getAction(); +            if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { +                String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); +                final String lockedReason = +                        intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); +                updateSimState(stateExtra, lockedReason); +                updateTelephony(); +            } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) { +                updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false), +                        intent.getStringExtra(TelephonyIntents.EXTRA_SPN), +                        intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false), +                        intent.getStringExtra(TelephonyIntents.EXTRA_PLMN)); +                notifyListenersIfNecessary(); +            } +        } -        if (!mHasMobileDataFeature) { -            mDataSignalIconId = mPhoneSignalIconId = 0; -            mQSPhoneSignalIconId = 0; -            mobileLabel = ""; -        } else { -            // We want to show the carrier name if in service and either: -            //   - We are connected to mobile data, or -            //   - We are not connected to mobile data, as long as the *reason* packets are not -            //     being routed over that link is that we have better connectivity via wifi. -            // If data is disconnected for some other reason but wifi (or ethernet/bluetooth) -            // is connected, we show nothing. -            // Otherwise (nothing connected) we show "No internet connection". - -            if (mDataConnected) { -                mobileLabel = mNetworkName; -            } else if (mConnected || emergencyOnly) { -                if (hasService() || emergencyOnly) { -                    // The isEmergencyOnly test covers the case of a phone with no SIM -                    mobileLabel = mNetworkName; +        /** +         * Determines the current sim state, based on a TelephonyIntents.ACTION_SIM_STATE_CHANGED +         * broadcast. +         */ +        private final void updateSimState(String stateExtra, String lockedReason) { +            if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { +                mSimState = IccCardConstants.State.ABSENT; +            } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { +                mSimState = IccCardConstants.State.READY; +            } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { +                if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { +                    mSimState = IccCardConstants.State.PIN_REQUIRED; +                } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { +                    mSimState = IccCardConstants.State.PUK_REQUIRED;                  } else { -                    // Tablets, basically -                    mobileLabel = ""; +                    mSimState = IccCardConstants.State.NETWORK_LOCKED;                  }              } else { -                mobileLabel -                    = context.getString(R.string.status_bar_settings_signal_meter_disconnected); +                mSimState = IccCardConstants.State.UNKNOWN;              } +            if (DEBUG) Log.d(TAG, "updateSimState: mSimState=" + mSimState); +        } -            // Now for things that should only be shown when actually using mobile data. -            if (mDataConnected) { -                combinedSignalIconId = mDataSignalIconId; - -                combinedLabel = mobileLabel; -                combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon() -                mContentDescriptionCombinedSignal = mContentDescriptionDataType; +        /** +         * Updates the network's name based on incoming spn and plmn. +         */ +        void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) { +            if (CHATTY) { +                Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn +                        + " showPlmn=" + showPlmn + " plmn=" + plmn); +            } +            StringBuilder str = new StringBuilder(); +            if (showPlmn && plmn != null) { +                str.append(plmn); +            } +            if (showSpn && spn != null) { +                if (str.length() != 0) { +                    str.append(mNetworkNameSeparator); +                } +                str.append(spn); +            } +            if (str.length() != 0) { +                mCurrentState.networkName = str.toString(); +            } else { +                mCurrentState.networkName = mNetworkNameDefault;              }          } -        if (mWifiConnected) { -            if (mWifiSsid == null) { -                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid); +        /** +         * Updates the current state based on mServiceState, mSignalStrength, mDataNetType, +         * mDataState, and mSimState.  It should be called any time one of these is updated. +         * This will call listeners if necessary. +         */ +        private final void updateTelephony() { +            if (DEBUG) { +                Log.d(TAG, "updateTelephonySignalStrength: hasService=" + hasService() +                        + " ss=" + mSignalStrength); +            } +            mCurrentState.connected = hasService() && mSignalStrength != null; +            if (mCurrentState.connected) { +                if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) { +                    mCurrentState.level = mSignalStrength.getCdmaLevel(); +                } else { +                    mCurrentState.level = mSignalStrength.getLevel(); +                } +            } +            if (mNetworkToIconLookup.containsKey(mDataNetType)) { +                mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);              } else { -                wifiLabel = mWifiSsid; -                if (DEBUG) { -                    wifiLabel += "xxxxXXXXxxxxXXXX"; +                mCurrentState.iconGroup = mDefaultIcons; +            } +            mCurrentState.dataConnected = mCurrentState.connected +                    && mDataState == TelephonyManager.DATA_CONNECTED; +            if (!isCdma()) { +                if (mSimState == IccCardConstants.State.READY || +                        mSimState == IccCardConstants.State.UNKNOWN) { +                    mCurrentState.noSim = false; +                } else { +                    mCurrentState.noSim = true; +                    // No sim, no data. +                    mCurrentState.dataConnected = false;                  }              } -            combinedLabel = wifiLabel; -            combinedSignalIconId = mWifiIconId; // set by updateWifiIcons() -            mContentDescriptionCombinedSignal = mContentDescriptionWifi; -        } else { -            if (mHasMobileDataFeature) { -                wifiLabel = ""; -            } else { -                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected); +            if (isRoaming()) { +                mCurrentState.iconGroup = TelephonyIcons.ROAMING; +            } +            if (isEmergencyOnly() != mCurrentState.isEmergency) { +                mCurrentState.isEmergency = isEmergencyOnly(); +                mNetworkController.recalculateEmergency();              } +            notifyListenersIfNecessary();          } -        if (mBluetoothTethered) { -            combinedLabel = mContext.getString(R.string.bluetooth_tethered); -            combinedSignalIconId = mBluetoothTetherIconId; -            mContentDescriptionCombinedSignal = mContext.getString( -                    R.string.accessibility_bluetooth_tether); +        @VisibleForTesting +        void setActivity(int activity) { +            mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT +                    || activity == TelephonyManager.DATA_ACTIVITY_IN; +            mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT +                    || activity == TelephonyManager.DATA_ACTIVITY_OUT; +            notifyListenersIfNecessary();          } -        final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET); -        if (ethernetConnected) { -            combinedLabel = context.getString(R.string.ethernet_label); +        @Override +        public void dump(PrintWriter pw) { +            super.dump(pw); +            pw.println("  mServiceState=" + mServiceState + ","); +            pw.println("  mSignalStrength=" + mSignalStrength + ","); +            pw.println("  mDataState=" + mDataState + ","); +            pw.println("  mDataNetType=" + mDataNetType + ",");          } -        if (mAirplaneMode && -                (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) { -            // Only display the flight-mode icon if not in "emergency calls only" mode. - -            // look again; your radios are now airplanes -            mContentDescriptionPhoneSignal = mContext.getString( -                    R.string.accessibility_airplane_mode); -            mAirplaneIconId = TelephonyIcons.FLIGHT_MODE_ICON; -            mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0; -            mQSPhoneSignalIconId = 0; - -            // combined values from connected wifi take precedence over airplane mode -            if (mWifiConnected) { -                // Suppress "No internet connection." from mobile if wifi connected. -                mobileLabel = ""; -            } else { -                if (mHasMobileDataFeature) { -                    // let the mobile icon show "No internet connection." -                    wifiLabel = ""; -                } else { -                    wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected); -                    combinedLabel = wifiLabel; +        PhoneStateListener mPhoneStateListener = new PhoneStateListener() { +            @Override +            public void onSignalStrengthsChanged(SignalStrength signalStrength) { +                if (DEBUG) { +                    Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength + +                            ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));                  } -                mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal; -                combinedSignalIconId = mDataSignalIconId; +                mSignalStrength = signalStrength; +                updateTelephony();              } -        } -        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) { -            // pretty much totally disconnected -            combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected); -            // On devices without mobile radios, we want to show the wifi icon -            combinedSignalIconId = -                mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId; -            mContentDescriptionCombinedSignal = mHasMobileDataFeature -                ? mContentDescriptionDataType : mContentDescriptionWifi; +            @Override +            public void onServiceStateChanged(ServiceState state) { +                if (DEBUG) { +                    Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState() +                            + " dataState=" + state.getDataRegState()); +                } +                mServiceState = state; +                updateTelephony(); +            } -            int inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_MOBILE); +            @Override +            public void onDataConnectionStateChanged(int state, int networkType) { +                if (DEBUG) { +                    Log.d(TAG, "onDataConnectionStateChanged: state=" + state +                            + " type=" + networkType); +                } +                mDataState = state; +                mDataNetType = networkType; +                updateTelephony(); +            } -            mDataTypeIconId = 0; -            mQSDataTypeIconId = 0; -            if (isRoaming()) { -                mDataTypeIconId = TelephonyIcons.ROAMING_ICON; -                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition]; +            @Override +            public void onDataActivity(int direction) { +                if (DEBUG) { +                    Log.d(TAG, "onDataActivity: direction=" + direction); +                } +                setActivity(direction); +            } +        }; + +        static class MobileIconGroup extends SignalController.IconGroup { +            final int mDataContentDescription; // mContentDescriptionDataType +            final int mDataType; +            final boolean mIsWide; +            final int[] mQsDataType; + +            public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc, +                    int sbNullState, int qsNullState, int sbDiscState, int qsDiscState, +                    int discContentDesc, int dataContentDesc, int dataType, boolean isWide, +                    int[] qsDataType) { +                super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState, +                        qsDiscState, discContentDesc); +                mDataContentDescription = dataContentDesc; +                mDataType = dataType; +                mIsWide = isWide; +                mQsDataType = qsDataType;              }          } -        if (mDemoMode) { -            mQSWifiIconId = mDemoWifiLevel < 0 ? R.drawable.ic_qs_wifi_no_network -                    : WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel]; -            mQSPhoneSignalIconId = mDemoMobileLevel < 0 ? R.drawable.ic_qs_signal_no_signal : -                    TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mDemoInetCondition][mDemoMobileLevel]; -            mQSDataTypeIconId = mDemoQSDataTypeIconId; -        } - -        if (DEBUG) { -            Log.d(TAG, "refreshViews connected={" -                    + (mWifiConnected?" wifi":"") -                    + (mDataConnected?" data":"") -                    + " } level=" -                    + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel())) -                    + " combinedSignalIconId=0x" -                    + Integer.toHexString(combinedSignalIconId) -                    + "/" + getResourceName(combinedSignalIconId) -                    + " mobileLabel=" + mobileLabel -                    + " wifiLabel=" + wifiLabel -                    + " emergencyOnly=" + emergencyOnly -                    + " combinedLabel=" + combinedLabel -                    + " mAirplaneMode=" + mAirplaneMode -                    + " mDataActivity=" + mDataActivity -                    + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId) -                    + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId) -                    + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId) -                    + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId) -                    + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId) -                    + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId) -                    + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId) -                    + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId) -                    + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId)); -        } +        static class MobileState extends SignalController.State { +            String networkName; +            boolean noSim; +            boolean dataConnected; +            boolean isEmergency; +            boolean airplaneMode; +            int inetForNetwork; -        // update QS -        for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) { -            notifySignalsChangedCallbacks(cb); -        } - -        if (mLastPhoneSignalIconId          != mPhoneSignalIconId -         || mLastWifiIconId                 != mWifiIconId -         || mLastInetCondition              != mInetCondition -         || mLastWimaxIconId                != mWimaxIconId -         || mLastDataTypeIconId             != mDataTypeIconId -         || mLastAirplaneMode               != mAirplaneMode -         || mLastLocale                     != mLocale -         || mLastConnectedNetworkType       != mConnectedNetworkType) -        { -            // NB: the mLast*s will be updated later -            for (SignalCluster cluster : mSignalClusters) { -                refreshSignalCluster(cluster); +            @Override +            public void copyFrom(State s) { +                MobileState state = (MobileState) s; +                noSim = state.noSim; +                networkName = state.networkName; +                dataConnected = state.dataConnected; +                inetForNetwork = state.inetForNetwork; +                isEmergency = state.isEmergency; +                airplaneMode = state.airplaneMode; +                super.copyFrom(s);              } -        } -        if (mLastAirplaneMode != mAirplaneMode) { -            mLastAirplaneMode = mAirplaneMode; -        } +            @Override +            protected void toString(StringBuilder builder) { +                builder.append("noSim=").append(noSim).append(','); +                builder.append("networkName=").append(networkName).append(','); +                builder.append("dataConnected=").append(dataConnected).append(','); +                builder.append("inetForNetwork=").append(inetForNetwork).append(','); +                builder.append("isEmergency=").append(isEmergency).append(','); +                builder.append("airplaneMode=").append(airplaneMode).append(','); +                super.toString(builder); +            } -        if (mLastLocale != mLocale) { -            mLastLocale = mLocale; +            @Override +            public boolean equals(Object o) { +                return super.equals(o) +                        && Objects.equals(((MobileState) o).networkName, networkName) +                        && ((MobileState) o).noSim == noSim +                        && ((MobileState) o).dataConnected == dataConnected +                        && ((MobileState) o).isEmergency == isEmergency +                        && ((MobileState) o).airplaneMode == airplaneMode +                        && ((MobileState) o).inetForNetwork == inetForNetwork; +            }          } +    } -        // the phone icon on phones -        if (mLastPhoneSignalIconId != mPhoneSignalIconId) { -            mLastPhoneSignalIconId = mPhoneSignalIconId; +    /** +     * Common base class for handling signal for both wifi and mobile data. +     */ +    static abstract class SignalController<T extends SignalController.State, +            I extends SignalController.IconGroup> { +        protected final String mTag; +        protected final T mCurrentState; +        protected final T mLastState; +        protected final int mNetworkType; +        protected final Context mContext; +        // The owner of the SignalController (i.e. NetworkController will maintain the following +        // lists and call notifyListeners whenever the list has changed to ensure everyone +        // is aware of current state. +        protected final List<NetworkSignalChangedCallback> mSignalsChangedCallbacks; +        protected final List<SignalCluster> mSignalClusters; +        protected final NetworkControllerImpl mNetworkController; + +        // Save the previous HISTORY_SIZE states for logging. +        private final State[] mHistory; +        // Where to copy the next state into. +        private int mHistoryIndex; + +        public SignalController(String tag, Context context, int type, +                List<NetworkSignalChangedCallback> signalCallbacks, +                List<SignalCluster> signalClusters, NetworkControllerImpl networkController) { +            mTag = TAG + "::" + tag; +            mNetworkController = networkController; +            mNetworkType = type; +            mContext = context; +            mSignalsChangedCallbacks = signalCallbacks; +            mSignalClusters = signalClusters; +            mCurrentState = cleanState(); +            mLastState = cleanState(); +            if (RECORD_HISTORY) { +                mHistory = new State[HISTORY_SIZE]; +                for (int i = 0; i < HISTORY_SIZE; i++) { +                    mHistory[i] = cleanState(); +                } +            }          } -        // the data icon on phones -        if (mLastDataDirectionIconId != mDataDirectionIconId) { -            mLastDataDirectionIconId = mDataDirectionIconId; +        public T getState() { +            return mCurrentState;          } -        // the wifi icon on phones -        if (mLastWifiIconId != mWifiIconId) { -            mLastWifiIconId = mWifiIconId; +        public int getNetworkType() { +            return mNetworkType;          } -        if (mLastInetCondition != mInetCondition) { -            mLastInetCondition = mInetCondition; +        public void setInetCondition(int inetCondition) { +            mCurrentState.inetCondition = inetCondition; +            notifyListenersIfNecessary();          } -        if (mLastConnectedNetworkType != mConnectedNetworkType) { -            mLastConnectedNetworkType = mConnectedNetworkType; +        // @VisibleForDemoMode +        /** +         * Used at the end of demo mode to clear out any ugly state that it has created. +         * Since we haven't had any callbacks, then isDirty will not have been triggered, +         * so we can just take the last good state directly from there. +         */ +        void resetLastState() { +            mCurrentState.copyFrom(mLastState);          } -        // the wimax icon on phones -        if (mLastWimaxIconId != mWimaxIconId) { -            mLastWimaxIconId = mWimaxIconId; -        } -        // the combined data signal icon -        if (mLastCombinedSignalIconId != combinedSignalIconId) { -            mLastCombinedSignalIconId = combinedSignalIconId; +        /** +         * Determines if the state of this signal controller has changed and +         * needs to trigger callbacks related to it. +         */ +        public boolean isDirty() { +            if (!mLastState.equals(mCurrentState)) { +                if (DEBUG) { +                    Log.d(mTag, "Change in state from: " + mLastState + "\n" +                            + "\tto: " + mCurrentState); +                } +                return true; +            } +            return false;          } -        // the data network type overlay -        if (mLastDataTypeIconId != mDataTypeIconId) { -            mLastDataTypeIconId = mDataTypeIconId; +        public void saveLastState() { +            if (RECORD_HISTORY) { +                recordLast(); +            } +            // Updates the current time. +            mCurrentState.time = System.currentTimeMillis(); +            mLastState.copyFrom(mCurrentState); +        } + +        /** +         * Gets the signal icon for QS based on current state of connected, enabled, and level. +         */ +        public int getQsCurrentIconId() { +            if (mCurrentState.connected) { +                return getIcons().mQsIcons[mCurrentState.inetCondition][mCurrentState.level]; +            } else if (mCurrentState.enabled) { +                return getIcons().mQsDiscState; +            } else { +                return getIcons().mQsNullState; +            }          } -        // the combinedLabel in the notification panel -        if (!mLastCombinedLabel.equals(combinedLabel)) { -            mLastCombinedLabel = combinedLabel; -            N = mCombinedLabelViews.size(); -            for (int i=0; i<N; i++) { -                TextView v = mCombinedLabelViews.get(i); -                v.setText(combinedLabel); +        /** +         * Gets the signal icon for SB based on current state of connected, enabled, and level. +         */ +        public int getCurrentIconId() { +            if (mCurrentState.connected) { +                return getIcons().mSbIcons[mCurrentState.inetCondition][mCurrentState.level]; +            } else if (mCurrentState.enabled) { +                return getIcons().mSbDiscState; +            } else { +                return getIcons().mSbNullState;              }          } -        // wifi label -        N = mWifiLabelViews.size(); -        for (int i=0; i<N; i++) { -            TextView v = mWifiLabelViews.get(i); -            v.setText(wifiLabel); -            if ("".equals(wifiLabel)) { -                v.setVisibility(View.GONE); +        /** +         * Gets the content description for the signal based on current state of connected and +         * level. +         */ +        public int getContentDescription() { +            if (mCurrentState.connected) { +                return getIcons().mContentDesc[mCurrentState.level];              } else { -                v.setVisibility(View.VISIBLE); +                return getIcons().mDiscContentDesc;              }          } -        // mobile label -        N = mMobileLabelViews.size(); -        for (int i=0; i<N; i++) { -            TextView v = mMobileLabelViews.get(i); -            v.setText(mobileLabel); -            if ("".equals(mobileLabel)) { -                v.setVisibility(View.GONE); -            } else { -                v.setVisibility(View.VISIBLE); +        protected void notifyListenersIfNecessary() { +            if (isDirty()) { +                saveLastState(); +                notifyListeners(); +                mNetworkController.refreshCarrierLabel();              }          } -        // e-call label -        N = mEmergencyViews.size(); -        for (int i=0; i<N; i++) { -            StatusBarHeaderView v = mEmergencyViews.get(i); -            v.setShowEmergencyCallsOnly(emergencyOnly); +        /** +         * Returns the resource if resId is not 0, and an empty string otherwise. +         */ +        protected String getStringIfExists(int resId) { +            return resId != 0 ? mContext.getString(resId) : "";          } -    } -    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { -        pw.println("NetworkController state:"); -        pw.println(String.format("  %s network type %d (%s)", -                mConnected?"CONNECTED":"DISCONNECTED", -                mConnectedNetworkType, mConnectedNetworkTypeName)); -        pw.println("  - telephony ------"); -        pw.print("  hasVoiceCallingFeature()="); -        pw.println(hasVoiceCallingFeature()); -        pw.print("  hasService()="); -        pw.println(hasService()); -        pw.print("  mHspaDataDistinguishable="); -        pw.println(mHspaDataDistinguishable); -        pw.print("  mDataConnected="); -        pw.println(mDataConnected); -        pw.print("  mSimState="); -        pw.println(mSimState); -        pw.print("  mPhoneState="); -        pw.println(mPhoneState); -        pw.print("  mDataState="); -        pw.println(mDataState); -        pw.print("  mDataActivity="); -        pw.println(mDataActivity); -        pw.print("  mDataNetType="); -        pw.print(mDataNetType); -        pw.print("/"); -        pw.println(TelephonyManager.getNetworkTypeName(mDataNetType)); -        pw.print("  mServiceState="); -        pw.println(mServiceState); -        pw.print("  mSignalStrength="); -        pw.println(mSignalStrength); -        pw.print("  mLastSignalLevel="); -        pw.println(mLastSignalLevel); -        pw.print("  mNetworkName="); -        pw.println(mNetworkName); -        pw.print("  mNetworkNameDefault="); -        pw.println(mNetworkNameDefault); -        pw.print("  mNetworkNameSeparator="); -        pw.println(mNetworkNameSeparator.replace("\n","\\n")); -        pw.print("  mPhoneSignalIconId=0x"); -        pw.print(Integer.toHexString(mPhoneSignalIconId)); -        pw.print("/"); -        pw.print("  mQSPhoneSignalIconId=0x"); -        pw.print(Integer.toHexString(mQSPhoneSignalIconId)); -        pw.print("/"); -        pw.println(getResourceName(mPhoneSignalIconId)); -        pw.print("  mDataDirectionIconId="); -        pw.print(Integer.toHexString(mDataDirectionIconId)); -        pw.print("/"); -        pw.println(getResourceName(mDataDirectionIconId)); -        pw.print("  mDataSignalIconId="); -        pw.print(Integer.toHexString(mDataSignalIconId)); -        pw.print("/"); -        pw.println(getResourceName(mDataSignalIconId)); -        pw.print("  mDataTypeIconId="); -        pw.print(Integer.toHexString(mDataTypeIconId)); -        pw.print("/"); -        pw.println(getResourceName(mDataTypeIconId)); -        pw.print("  mQSDataTypeIconId="); -        pw.print(Integer.toHexString(mQSDataTypeIconId)); -        pw.print("/"); -        pw.println(getResourceName(mQSDataTypeIconId)); - -        pw.println("  - wifi ------"); -        pw.print("  mWifiEnabled="); -        pw.println(mWifiEnabled); -        pw.print("  mWifiConnected="); -        pw.println(mWifiConnected); -        pw.print("  mWifiRssi="); -        pw.println(mWifiRssi); -        pw.print("  mWifiLevel="); -        pw.println(mWifiLevel); -        pw.print("  mWifiSsid="); -        pw.println(mWifiSsid); -        pw.println(String.format("  mWifiIconId=0x%08x/%s", -                    mWifiIconId, getResourceName(mWifiIconId))); -        pw.println(String.format("  mQSWifiIconId=0x%08x/%s", -                    mQSWifiIconId, getResourceName(mQSWifiIconId))); -        pw.print("  mWifiActivity="); -        pw.println(mWifiActivity); - -        if (mWimaxSupported) { -            pw.println("  - wimax ------"); -            pw.print("  mIsWimaxEnabled="); pw.println(mIsWimaxEnabled); -            pw.print("  mWimaxConnected="); pw.println(mWimaxConnected); -            pw.print("  mWimaxIdle="); pw.println(mWimaxIdle); -            pw.println(String.format("  mWimaxIconId=0x%08x/%s", -                        mWimaxIconId, getResourceName(mWimaxIconId))); -            pw.println(String.format("  mWimaxSignal=%d", mWimaxSignal)); -            pw.println(String.format("  mWimaxState=%d", mWimaxState)); -            pw.println(String.format("  mWimaxExtraState=%d", mWimaxExtraState)); +        protected I getIcons() { +            return (I) mCurrentState.iconGroup;          } -        pw.println("  - Bluetooth ----"); -        pw.print("  mBtReverseTethered="); -        pw.println(mBluetoothTethered); +        /** +         * Saves the last state of any changes, so we can log the current +         * and last value of any state data. +         */ +        protected void recordLast() { +            mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)].copyFrom(mLastState); +        } -        pw.println("  - connectivity ------"); -        pw.print("  mInetCondition="); -        pw.println(mInetCondition); +        public void dump(PrintWriter pw) { +            pw.println("  - " + mTag + " -----"); +            pw.println("  Current State: " + mCurrentState); +            if (RECORD_HISTORY) { +                // Count up the states that actually contain time stamps, and only display those. +                int size = 0; +                for (int i = 0; i < HISTORY_SIZE; i++) { +                    if (mHistory[i].time != 0) size++; +                } +                // Print out the previous states in ordered number. +                for (int i = mHistoryIndex + HISTORY_SIZE - 1; +                        i >= mHistoryIndex + HISTORY_SIZE - size; i--) { +                    pw.println("  Previous State(" + (mHistoryIndex + HISTORY_SIZE - i) + ": " +                            + mHistory[i & (HISTORY_SIZE - 1)]); +                } +            } +        } -        pw.println("  - icons ------"); -        pw.print("  mLastPhoneSignalIconId=0x"); -        pw.print(Integer.toHexString(mLastPhoneSignalIconId)); -        pw.print("/"); -        pw.println(getResourceName(mLastPhoneSignalIconId)); -        pw.print("  mLastDataDirectionIconId=0x"); -        pw.print(Integer.toHexString(mLastDataDirectionIconId)); -        pw.print("/"); -        pw.println(getResourceName(mLastDataDirectionIconId)); -        pw.print("  mLastWifiIconId=0x"); -        pw.print(Integer.toHexString(mLastWifiIconId)); -        pw.print("/"); -        pw.println(getResourceName(mLastWifiIconId)); -        pw.print("  mLastCombinedSignalIconId=0x"); -        pw.print(Integer.toHexString(mLastCombinedSignalIconId)); -        pw.print("/"); -        pw.println(getResourceName(mLastCombinedSignalIconId)); -        pw.print("  mLastDataTypeIconId=0x"); -        pw.print(Integer.toHexString(mLastDataTypeIconId)); -        pw.print("/"); -        pw.println(getResourceName(mLastDataTypeIconId)); -        pw.print("  mLastCombinedLabel="); -        pw.print(mLastCombinedLabel); -        pw.println(""); -    } +        /** +         * Trigger callbacks based on current state.  The callbacks should be completely +         * based on current state, and only need to be called in the scenario where +         * mCurrentState != mLastState. +         */ +        public abstract void notifyListeners(); + +        /** +         * Generate a blank T. +         */ +        public abstract T cleanState(); + +        /* +         * Holds icons for a given state. Arrays are generally indexed as inet +         * state (full connectivity or not) first, and second dimension as +         * signal strength. +         */ +        static class IconGroup { +            final int[][] mSbIcons; +            final int[][] mQsIcons; +            final int[] mContentDesc; +            final int mSbNullState; +            final int mQsNullState; +            final int mSbDiscState; +            final int mQsDiscState; +            final int mDiscContentDesc; +            // For logging. +            final String mName; + +            public IconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc, +                    int sbNullState, int qsNullState, int sbDiscState, int qsDiscState, +                    int discContentDesc) { +                mName = name; +                mSbIcons = sbIcons; +                mQsIcons = qsIcons; +                mContentDesc = contentDesc; +                mSbNullState = sbNullState; +                mQsNullState = qsNullState; +                mSbDiscState = sbDiscState; +                mQsDiscState = qsDiscState; +                mDiscContentDesc = discContentDesc; +            } -    private String getResourceName(int resId) { -        if (resId != 0) { -            final Resources res = mContext.getResources(); -            try { -                return res.getResourceName(resId); -            } catch (android.content.res.Resources.NotFoundException ex) { -                return "(unknown)"; +            @Override +            public String toString() { +                return "IconGroup(" + mName + ")";              } -        } else { -            return "(null)";          } -    } -    private boolean mDemoMode; -    private int mDemoInetCondition; -    private int mDemoWifiLevel; -    private int mDemoDataTypeIconId; -    private int mDemoQSDataTypeIconId; -    private int mDemoMobileLevel; - -    @Override -    public void dispatchDemoCommand(String command, Bundle args) { -        if (!mDemoMode && command.equals(COMMAND_ENTER)) { -            mDemoMode = true; -            mDemoWifiLevel = mWifiLevel; -            mDemoInetCondition = mInetCondition; -            mDemoDataTypeIconId = mDataTypeIconId; -            mDemoQSDataTypeIconId = mQSDataTypeIconId; -            mDemoMobileLevel = mLastSignalLevel; -        } else if (mDemoMode && command.equals(COMMAND_EXIT)) { -            mDemoMode = false; -            for (SignalCluster cluster : mSignalClusters) { -                refreshSignalCluster(cluster); +        static class State { +            boolean connected; +            boolean enabled; +            boolean activityIn; +            boolean activityOut; +            int level; +            IconGroup iconGroup; +            int inetCondition; +            int rssi; // Only for logging. + +            // Not used for comparison, just used for logging. +            long time; + +            public void copyFrom(State state) { +                connected = state.connected; +                enabled = state.enabled; +                level = state.level; +                iconGroup = state.iconGroup; +                inetCondition = state.inetCondition; +                activityIn = state.activityIn; +                activityOut = state.activityOut; +                rssi = state.rssi; +                time = state.time;              } -            refreshViews(); -        } else if (mDemoMode && command.equals(COMMAND_NETWORK)) { -            String airplane = args.getString("airplane"); -            if (airplane != null) { -                boolean show = airplane.equals("show"); -                for (SignalCluster cluster : mSignalClusters) { -                    cluster.setIsAirplaneMode(show, TelephonyIcons.FLIGHT_MODE_ICON); + +            @Override +            public String toString() { +                if (time != 0) { +                    StringBuilder builder = new StringBuilder(); +                    toString(builder); +                    return builder.toString(); +                } else { +                    return "Empty " + getClass().getSimpleName();                  }              } -            String fully = args.getString("fully"); -            if (fully != null) { -                mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0; -            } -            String wifi = args.getString("wifi"); -            if (wifi != null) { -                boolean show = wifi.equals("show"); -                String level = args.getString("level"); -                if (level != null) { -                    mDemoWifiLevel = level.equals("null") ? -1 -                            : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1); -                } -                int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null -                        : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel]; -                for (SignalCluster cluster : mSignalClusters) { -                    cluster.setWifiIndicators( -                            show, -                            iconId, -                            "Demo"); -                } -                refreshViews(); + +            protected void toString(StringBuilder builder) { +                builder.append("connected=").append(connected).append(',') +                        .append("enabled=").append(enabled).append(',') +                        .append("level=").append(level).append(',') +                        .append("inetCondition=").append(inetCondition).append(',') +                        .append("iconGroup=").append(iconGroup).append(',') +                        .append("activityIn=").append(activityIn).append(',') +                        .append("activityOut=").append(activityOut).append(',') +                        .append("rssi=").append(rssi).append(',') +                        .append("lastModified=").append(DateFormat.format("MM-dd hh:mm:ss", time));              } -            String mobile = args.getString("mobile"); -            if (mobile != null) { -                boolean show = mobile.equals("show"); -                String datatype = args.getString("datatype"); -                if (datatype != null) { -                    mDemoDataTypeIconId = -                            datatype.equals("1x") ? TelephonyIcons.ICON_1X : -                            datatype.equals("3g") ? TelephonyIcons.ICON_3G : -                            datatype.equals("4g") ? TelephonyIcons.ICON_4G : -                            datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e : -                            datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g : -                            datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h : -                            datatype.equals("lte") ? TelephonyIcons.ICON_LTE : -                            datatype.equals("roam") ? TelephonyIcons.ROAMING_ICON : -                            0; -                    mDemoQSDataTypeIconId = -                            datatype.equals("1x") ? TelephonyIcons.QS_ICON_1X : -                            datatype.equals("3g") ? TelephonyIcons.QS_ICON_3G : -                            datatype.equals("4g") ? TelephonyIcons.QS_ICON_4G : -                            datatype.equals("e") ? R.drawable.ic_qs_signal_e : -                            datatype.equals("g") ? R.drawable.ic_qs_signal_g : -                            datatype.equals("h") ? R.drawable.ic_qs_signal_h : -                            datatype.equals("lte") ? TelephonyIcons.QS_ICON_LTE : -                            datatype.equals("roam") ? R.drawable.ic_qs_signal_r : -                            0; -                } -                int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH; -                String level = args.getString("level"); -                if (level != null) { -                    mDemoMobileLevel = level.equals("null") ? -1 -                            : Math.min(Integer.parseInt(level), icons[0].length - 1); -                } -                int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null : -                        icons[mDemoInetCondition][mDemoMobileLevel]; -                for (SignalCluster cluster : mSignalClusters) { -                    cluster.setMobileDataIndicators( -                            show, -                            iconId, -                            mDemoDataTypeIconId, -                            "Demo", -                            "Demo", -                            isTypeIconWide(mDemoDataTypeIconId)); + +            @Override +            public boolean equals(Object o) { +                if (!o.getClass().equals(getClass())) { +                    return false;                  } -                refreshViews(); +                State other = (State) o; +                return other.connected == connected +                        && other.enabled == enabled +                        && other.level == level +                        && other.inetCondition == inetCondition +                        && other.iconGroup == iconGroup +                        && other.activityIn == activityIn +                        && other.activityOut == activityOut +                        && other.rssi == rssi;              }          }      } + +    public interface SignalCluster { +        void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription); + +        void setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon, +                String contentDescription, String typeContentDescription, boolean isTypeIconWide); + +        void setIsAirplaneMode(boolean is, int airplaneIcon, int contentDescription); +    } + +    public interface EmergencyListener { +        void setEmergencyCallsOnly(boolean emergencyOnly); +    } + +    public interface CarrierLabelListener { +        void setCarrierLabel(String label); +    } + +    @VisibleForTesting +    static class Config { +        boolean showAtLeastThreeGees = false; +        boolean alwaysShowCdmaRssi = false; +        boolean show4gForLte = false; +        boolean hspaDataDistinguishable; + +        static Config readConfig(Context context) { +            Config config = new Config(); +            Resources res = context.getResources(); + +            config.showAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G); +            config.alwaysShowCdmaRssi = +                    res.getBoolean(com.android.internal.R.bool.config_alwaysUseCdmaRssi); +            config.show4gForLte = res.getBoolean(R.bool.config_show4GForLTE); +            config.hspaDataDistinguishable = +                    res.getBoolean(R.bool.config_hspa_data_distinguishable); +            return config; +        } +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java index 1f2b91895a75..4091619aa879 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java @@ -17,11 +17,16 @@  package com.android.systemui.statusbar.policy;  import com.android.systemui.R; +import com.android.systemui.statusbar.policy.NetworkControllerImpl.MobileSignalController.MobileIconGroup;  class TelephonyIcons {      //***** Signal strength icons +    static final int TELEPHONY_NUM_LEVELS = 5; +      //GSM/UMTS +    static final int TELEPHONY_NO_NETWORK = R.drawable.stat_sys_signal_null; +      static final int[][] TELEPHONY_SIGNAL_STRENGTH = {          { R.drawable.stat_sys_signal_0,            R.drawable.stat_sys_signal_1, @@ -35,6 +40,8 @@ class TelephonyIcons {            R.drawable.stat_sys_signal_4_fully }      }; +    static final int QS_TELEPHONY_NO_NETWORK = R.drawable.ic_qs_signal_no_signal; +      static final int[][] QS_TELEPHONY_SIGNAL_STRENGTH = {          { R.drawable.ic_qs_signal_0,            R.drawable.ic_qs_signal_1, @@ -66,8 +73,6 @@ class TelephonyIcons {          R.drawable.ic_qs_signal_r      }; -    static final int[][] DATA_SIGNAL_STRENGTH = TELEPHONY_SIGNAL_STRENGTH; -      //***** Data connection icons      //GSM/UMTS @@ -191,6 +196,9 @@ class TelephonyIcons {      static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;      static final int ROAMING_ICON = R.drawable.stat_sys_data_fully_connected_roam;      static final int ICON_LTE = R.drawable.stat_sys_data_fully_connected_lte; +    static final int ICON_G = R.drawable.stat_sys_data_fully_connected_g; +    static final int ICON_E = R.drawable.stat_sys_data_fully_connected_e; +    static final int ICON_H = R.drawable.stat_sys_data_fully_connected_h;      static final int ICON_3G = R.drawable.stat_sys_data_fully_connected_3g;      static final int ICON_4G = R.drawable.stat_sys_data_fully_connected_4g;      static final int ICON_1X = R.drawable.stat_sys_data_fully_connected_1x; @@ -199,5 +207,137 @@ class TelephonyIcons {      static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g;      static final int QS_ICON_4G = R.drawable.ic_qs_signal_4g;      static final int QS_ICON_1X = R.drawable.ic_qs_signal_1x; + +    static final MobileIconGroup THREE_G = new MobileIconGroup( +            "3G", +            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, +            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, +            0, 0, +            TelephonyIcons.TELEPHONY_NO_NETWORK, +            TelephonyIcons.QS_TELEPHONY_NO_NETWORK, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], +            R.string.accessibility_data_connection_3g, +            TelephonyIcons.ICON_3G, +            true, +            TelephonyIcons.QS_DATA_3G +            ); + +    static final MobileIconGroup UNKNOWN = new MobileIconGroup( +            "Unknown", +            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, +            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, +            0, 0, +            TelephonyIcons.TELEPHONY_NO_NETWORK, +            TelephonyIcons.QS_TELEPHONY_NO_NETWORK, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], +            0, 0, false, new int[2] +            ); + +    static final MobileIconGroup E = new MobileIconGroup( +            "E", +            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, +            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, +            0, 0, +            TelephonyIcons.TELEPHONY_NO_NETWORK, +            TelephonyIcons.QS_TELEPHONY_NO_NETWORK, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], +            R.string.accessibility_data_connection_edge, +            TelephonyIcons.ICON_E, +            false, +            TelephonyIcons.QS_DATA_E +            ); + +    static final MobileIconGroup ONE_X = new MobileIconGroup( +            "1X", +            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, +            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, +            0, 0, +            TelephonyIcons.TELEPHONY_NO_NETWORK, +            TelephonyIcons.QS_TELEPHONY_NO_NETWORK, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], +            R.string.accessibility_data_connection_cdma, +            TelephonyIcons.ICON_1X, +            true, +            TelephonyIcons.QS_DATA_1X +            ); + +    static final MobileIconGroup G = new MobileIconGroup( +            "G", +            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, +            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, +            0, 0, +            TelephonyIcons.TELEPHONY_NO_NETWORK, +            TelephonyIcons.QS_TELEPHONY_NO_NETWORK, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], +            R.string.accessibility_data_connection_gprs, +            TelephonyIcons.ICON_G, +            false, +            TelephonyIcons.QS_DATA_G +            ); + +    static final MobileIconGroup H = new MobileIconGroup( +            "H", +            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, +            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, +            0, 0, +            TelephonyIcons.TELEPHONY_NO_NETWORK, +            TelephonyIcons.QS_TELEPHONY_NO_NETWORK, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], +            R.string.accessibility_data_connection_3_5g, +            TelephonyIcons.ICON_H, +            false, +            TelephonyIcons.QS_DATA_H +            ); + +    static final MobileIconGroup FOUR_G = new MobileIconGroup( +            "4G", +            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, +            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, +            0, 0, +            TelephonyIcons.TELEPHONY_NO_NETWORK, +            TelephonyIcons.QS_TELEPHONY_NO_NETWORK, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], +            R.string.accessibility_data_connection_4g, +            TelephonyIcons.ICON_4G, +            true, +            TelephonyIcons.QS_DATA_4G +            ); + +    static final MobileIconGroup LTE = new MobileIconGroup( +            "LTE", +            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, +            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, +            0, 0, +            TelephonyIcons.TELEPHONY_NO_NETWORK, +            TelephonyIcons.QS_TELEPHONY_NO_NETWORK, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], +            R.string.accessibility_data_connection_lte, +            TelephonyIcons.ICON_LTE, +            true, +            TelephonyIcons.QS_DATA_LTE +            ); + +    static final MobileIconGroup ROAMING = new MobileIconGroup( +            "Roaming", +            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING, +            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, +            0, 0, +            TelephonyIcons.TELEPHONY_NO_NETWORK, +            TelephonyIcons.QS_TELEPHONY_NO_NETWORK, +            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], +            R.string.accessibility_data_connection_roaming, +            TelephonyIcons.ROAMING_ICON, +            false, +            TelephonyIcons.QS_DATA_R +            );  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java index 49af97923ecc..c56646fc7740 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java @@ -45,5 +45,8 @@ class WifiIcons {                R.drawable.ic_qs_wifi_full_4 }          }; +    static final int QS_WIFI_NO_NETWORK = R.drawable.ic_qs_wifi_no_network; +    static final int WIFI_NO_NETWORK = R.drawable.stat_sys_wifi_signal_null; +      static final int WIFI_LEVEL_COUNT = WIFI_SIGNAL_STRENGTH[0].length;  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java deleted file mode 100644 index 48778282972e..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.policy; - -import com.android.systemui.statusbar.policy.TelephonyIcons; - -class WimaxIcons { -    static final int[][] WIMAX_SIGNAL_STRENGTH = TelephonyIcons.DATA_SIGNAL_STRENGTH; - -    static final int WIMAX_DISCONNECTED = WIMAX_SIGNAL_STRENGTH[0][0]; - -    static final int WIMAX_IDLE = WIMAX_DISCONNECTED; // XXX: unclear if we need a different icon -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 10cffc49574b..49fe1e3f0c34 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -17,6 +17,7 @@ import android.util.Log;  import com.android.internal.telephony.cdma.EriInfo;  import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; +import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;  import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;  import org.mockito.ArgumentCaptor; @@ -44,6 +45,7 @@ public class NetworkControllerBaseTest extends AndroidTestCase {      protected ConnectivityManager mMockCm;      protected WifiManager mMockWm;      protected TelephonyManager mMockTm; +    protected Config mConfig;      @Override      protected void setUp() throws Exception { @@ -59,16 +61,19 @@ public class NetworkControllerBaseTest extends AndroidTestCase {          mSignalStrength = mock(SignalStrength.class);          mServiceState = mock(ServiceState.class); -        mSignalCluster = mock(SignalCluster.class); -        mNetworkSignalChangedCallback = mock(NetworkSignalChangedCallback.class); +        mConfig = new Config(); +        mConfig.hspaDataDistinguishable = true;          mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, -                mock(AccessPointController.class), mock(MobileDataController.class)); +                mConfig, mock(AccessPointControllerImpl.class), +                mock(MobileDataControllerImpl.class));          setupNetworkController();      }      protected void setupNetworkController() { -        mPhoneStateListener = mNetworkController.mPhoneStateListener; +        mPhoneStateListener = mNetworkController.mMobileSignalController.mPhoneStateListener; +        mSignalCluster = mock(SignalCluster.class); +        mNetworkSignalChangedCallback = mock(NetworkSignalChangedCallback.class);          mNetworkController.addSignalCluster(mSignalCluster);          mNetworkController.addNetworkSignalChangedCallback(mNetworkSignalChangedCallback);      } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index af053094352f..bb2ff7c67a9a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -18,7 +18,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {          Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);          // Create a new NetworkController as this is currently handled in constructor.          mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, -                mock(AccessPointController.class), mock(MobileDataController.class)); +                mConfig, mock(AccessPointControllerImpl.class), +                mock(MobileDataControllerImpl.class));          setupNetworkController();          verifyLastMobileDataIndicators(false, 0, 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java index 4ffdff280b44..7f0a8f4dd1ae 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java @@ -6,8 +6,6 @@ import android.net.NetworkInfo;  import android.net.wifi.WifiInfo;  import android.net.wifi.WifiManager; -import com.android.systemui.R; -  import org.mockito.ArgumentCaptor;  import org.mockito.Mockito; @@ -16,14 +14,10 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {      private static final int MIN_RSSI = -100;      private static final int MAX_RSSI = -55; -    // TODO: Move this into WifiIcons, remove all R.drawable from NetworkControllerImpl. -    private static final int NULL_SIGNAL = R.drawable.stat_sys_wifi_signal_null; -    private static final int QS_NO_NET = R.drawable.ic_qs_wifi_no_network; -      public void testWifiIcon() {          String testSsid = "Test SSID";          setWifiEnabled(true); -        verifyLastWifiIcon(false, NULL_SIGNAL); +        verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);          setWifiState(true, testSsid);          verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]); @@ -42,10 +36,10 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {          String testSsid = "Test SSID";          setWifiEnabled(false); -        verifyLastQsWifiIcon(false, false, 0, null); +        verifyLastQsWifiIcon(false, false, WifiIcons.QS_WIFI_NO_NETWORK, null);          setWifiEnabled(true); -        verifyLastQsWifiIcon(true, false, QS_NO_NET, null); +        verifyLastQsWifiIcon(true, false, WifiIcons.QS_WIFI_NO_NETWORK, null);          setWifiState(true, testSsid);          for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { @@ -118,8 +112,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {      protected void setWifiActivity(int activity) {          // TODO: Not this, because this variable probably isn't sticking around. -        mNetworkController.mWifiActivity = activity; -        mNetworkController.refreshViews(); +        mNetworkController.mWifiSignalController.setActivity(activity);      }      protected void setWifiLevel(int level) {  |