OSDN Git Service

Add a status bar icon for Ethernet.
authorLorenzo Colitti <lorenzo@google.com>
Mon, 27 Apr 2015 11:32:01 +0000 (20:32 +0900)
committerLorenzo Colitti <lorenzo@google.com>
Sat, 2 May 2015 01:43:31 +0000 (10:43 +0900)
Bug: 20613953
Change-Id: I52970b4f5fb6429876d1a2eb195a834c9e020021

packages/SystemUI/res/drawable/stat_sys_ethernet.xml [new file with mode: 0644]
packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml [new file with mode: 0644]
packages/SystemUI/res/layout/signal_cluster_view.xml
packages/SystemUI/res/values/strings.xml
packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetIcons.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java [new file with mode: 0644]

diff --git a/packages/SystemUI/res/drawable/stat_sys_ethernet.xml b/packages/SystemUI/res/drawable/stat_sys_ethernet.xml
new file mode 100644 (file)
index 0000000..e765320
--- /dev/null
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="18.77dp"
+        android:height="17dp"
+        android:viewportWidth="53.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M15.54 13.52l-3.08-2.55L1.64 24l10.82 13.04 3.08-2.55L6.84 24l8.7-10.48zM14 26h4v-4h-4v4zm20-4h-4v4h4v-4zm-12 4h4v-4h-4v4zm13.54-15.04l-3.08 2.55L41.16 24l-8.7 10.48 3.08 2.55L46.36 24 35.54 10.96z"/>
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M49.000000,40.000000l4.000000,0.000000l0.000000,4.000000l-4.000000,0.000000z"/>
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M49.000000,20.000000l4.000000,0.000000l0.000000,16.100000l-4.000000,0.000000z"/></vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml b/packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml
new file mode 100644 (file)
index 0000000..b7b154c
--- /dev/null
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18.77dp"
+        android:height="17dp"
+        android:viewportWidth="53.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M15.54 13.52l-3.08-2.55L1.64 24l10.82 13.04 3.08-2.55L6.84 24l8.7-10.48zM14 26h4v-4h-4v4zm20-4h-4v4h4v-4zm-12 4h4v-4h-4v4zm13.54-15.04l-3.08 2.55L41.16 24l-8.7 10.48 3.08 2.55L46.36 24 35.54 10.96z"/>
+</vector>
index c9edef8..69dcad2 100644 (file)
         android:src="@drawable/stat_sys_vpn_ic"
         />
     <FrameLayout
+        android:id="@+id/ethernet_combo"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        >
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:theme="@style/DualToneLightTheme"
+            android:id="@+id/ethernet"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            />
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:theme="@style/DualToneDarkTheme"
+            android:id="@+id/ethernet_dark"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:alpha="0.0"
+            />
+    </FrameLayout>
+    <FrameLayout
         android:id="@+id/wifi_combo"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
index f3a2912..ecc1b61 100644 (file)
     <!-- Content description of the WiMAX signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_wimax_signal_full">WiMAX signal full.</string>
 
+    <!-- Content description of the Ethernet connection when disconnected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_ethernet_disconnected">Ethernet disconnected.</string>
+    <!-- Content description of the Ethernet connection when connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_ethernet_connected">Ethernet connected.</string>
+
     <!-- Content description of an item with no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_no_signal">No signal.</string>
     <!-- Content description of an item with no signal and no connection for accessibility (not shown on the screen) [CHAR LIMIT=NONE] -->
index b2bb021..f6629dd 100644 (file)
@@ -53,18 +53,21 @@ public class SignalClusterView
 
     private boolean mNoSimsVisible = false;
     private boolean mVpnVisible = false;
+    private boolean mEthernetVisible = false;
+    private int mEthernetIconId = 0;
     private boolean mWifiVisible = false;
     private int mWifiStrengthId = 0;
     private boolean mIsAirplaneMode = false;
     private int mAirplaneIconId = 0;
     private int mAirplaneContentDescription;
     private String mWifiDescription;
+    private String mEthernetDescription;
     private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
     private int mIconTint = Color.WHITE;
     private float mDarkIntensity;
 
-    ViewGroup mWifiGroup;
-    ImageView mVpn, mWifi, mAirplane, mNoSims, mWifiDark, mNoSimsDark;
+    ViewGroup mEthernetGroup, mWifiGroup;
+    ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark;
     View mWifiAirplaneSpacer;
     View mWifiSignalSpacer;
     LinearLayout mMobileSignalGroup;
@@ -116,6 +119,9 @@ public class SignalClusterView
         super.onAttachedToWindow();
 
         mVpn            = (ImageView) findViewById(R.id.vpn);
+        mEthernetGroup  = (ViewGroup) findViewById(R.id.ethernet_combo);
+        mEthernet       = (ImageView) findViewById(R.id.ethernet);
+        mEthernetDark   = (ImageView) findViewById(R.id.ethernet_dark);
         mWifiGroup      = (ViewGroup) findViewById(R.id.wifi_combo);
         mWifi           = (ImageView) findViewById(R.id.wifi_signal);
         mWifiDark       = (ImageView) findViewById(R.id.wifi_signal_dark);
@@ -136,6 +142,8 @@ public class SignalClusterView
     @Override
     protected void onDetachedFromWindow() {
         mVpn            = null;
+        mEthernetGroup  = null;
+        mEthernet       = null;
         mWifiGroup      = null;
         mWifi           = null;
         mAirplane       = null;
@@ -183,6 +191,15 @@ public class SignalClusterView
     }
 
     @Override
+    public void setEthernetIndicators(boolean visible, int icon, String contentDescription) {
+        mEthernetVisible = visible;
+        mEthernetIconId = icon;
+        mEthernetDescription = contentDescription;
+
+        apply();
+    }
+
+    @Override
     public void setNoSims(boolean show) {
         mNoSimsVisible = show;
     }
@@ -234,6 +251,9 @@ public class SignalClusterView
     public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         // Standard group layout onPopulateAccessibilityEvent() implementations
         // ignore content description, so populate manually
+        if (mEthernetVisible && mEthernetGroup != null &&
+                mEthernetGroup.getContentDescription() != null)
+            event.getText().add(mEthernetGroup.getContentDescription());
         if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null)
             event.getText().add(mWifiGroup.getContentDescription());
         for (PhoneState state : mPhoneStates) {
@@ -246,6 +266,10 @@ public class SignalClusterView
     public void onRtlPropertiesChanged(int layoutDirection) {
         super.onRtlPropertiesChanged(layoutDirection);
 
+        if (mEthernet != null) {
+            mEthernet.setImageDrawable(null);
+        }
+
         if (mWifi != null) {
             mWifi.setImageDrawable(null);
         }
@@ -277,6 +301,21 @@ public class SignalClusterView
 
         mVpn.setVisibility(mVpnVisible ? View.VISIBLE : View.GONE);
         if (DEBUG) Log.d(TAG, String.format("vpn: %s", mVpnVisible ? "VISIBLE" : "GONE"));
+
+        if (mEthernetVisible) {
+            mEthernet.setImageResource(mEthernetIconId);
+            mEthernetDark.setImageResource(mEthernetIconId);
+            mEthernetGroup.setContentDescription(mEthernetDescription);
+            mEthernetGroup.setVisibility(View.VISIBLE);
+        } else {
+            mEthernetGroup.setVisibility(View.GONE);
+        }
+
+        if (DEBUG) Log.d(TAG,
+                String.format("ethernet: %s",
+                    (mEthernetVisible ? "VISIBLE" : "GONE")));
+
+
         if (mWifiVisible) {
             mWifi.setImageResource(mWifiStrengthId);
             mWifiDark.setImageResource(mWifiStrengthId);
@@ -327,7 +366,7 @@ public class SignalClusterView
         mNoSimsDark.setVisibility(mNoSimsVisible ? View.VISIBLE : View.GONE);
 
         boolean anythingVisible = mNoSimsVisible || mWifiVisible || mIsAirplaneMode
-                || anyMobileVisible || mVpnVisible;
+                || anyMobileVisible || mVpnVisible || mEthernetVisible;
         setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
     }
 
@@ -345,6 +384,7 @@ public class SignalClusterView
         setTint(mAirplane, mIconTint);
         applyDarkIntensity(mDarkIntensity, mNoSims, mNoSimsDark);
         applyDarkIntensity(mDarkIntensity, mWifi, mWifiDark);
+        applyDarkIntensity(mDarkIntensity, mEthernet, mEthernetDark);
         for (int i = 0; i < mPhoneStates.size(); i++) {
             mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity);
         }
index 63fcbc5..8f86e2d 100644 (file)
@@ -35,4 +35,9 @@ public class AccessibilityContentDescriptions {
     };
 
     static final int WIFI_NO_CONNECTION = R.string.accessibility_no_wifi;
+
+    static final int[] ETHERNET_CONNECTION_VALUES = {
+        R.string.accessibility_ethernet_disconnected,
+        R.string.accessibility_ethernet_connected,
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetIcons.java
new file mode 100644 (file)
index 0000000..b391bd9
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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.R;
+
+class EthernetIcons {
+    static final int[][] ETHERNET_ICONS = {
+            { R.drawable.stat_sys_ethernet },
+            { R.drawable.stat_sys_ethernet_fully },
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
new file mode 100644 (file)
index 0000000..9c044c4
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 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 android.content.Context;
+import android.net.NetworkCapabilities;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
+
+import java.util.List;
+import java.util.Objects;
+
+
+public class EthernetSignalController extends
+        SignalController<SignalController.State, SignalController.IconGroup> {
+
+    public EthernetSignalController(Context context,
+            List<NetworkSignalChangedCallback> signalCallbacks,
+            List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
+        super("EthernetSignalController", context, NetworkCapabilities.TRANSPORT_ETHERNET,
+                signalCallbacks, signalClusters, networkController);
+        mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
+                "Ethernet Icons",
+                EthernetIcons.ETHERNET_ICONS,
+                null,
+                AccessibilityContentDescriptions.ETHERNET_CONNECTION_VALUES,
+                0, 0, 0, 0,
+                AccessibilityContentDescriptions.ETHERNET_CONNECTION_VALUES[0]);
+    }
+
+    @Override
+    public void notifyListeners() {
+        boolean ethernetVisible = mCurrentState.connected;
+        String contentDescription = getStringIfExists(getContentDescription());
+
+        // TODO: wire up data transfer using WifiSignalPoller.
+        int signalClustersLength = mSignalClusters.size();
+        for (int i = 0; i < signalClustersLength; i++) {
+            mSignalClusters.get(i).setEthernetIndicators(ethernetVisible, getCurrentIconId(),
+                    contentDescription);
+        }
+    }
+
+    @Override
+    public SignalController.State cleanState() {
+        return new SignalController.State();
+    }
+
+    public void setConnected(boolean connected) {
+        mCurrentState.connected = connected;
+        notifyListenersIfNecessary();
+    }
+}
index 9adf028..6d88535 100644 (file)
@@ -73,6 +73,10 @@ public class NetworkControllerImpl extends BroadcastReceiver
     // Subcontrollers.
     @VisibleForTesting
     final WifiSignalController mWifiSignalController;
+
+    @VisibleForTesting
+    final EthernetSignalController mEthernetSignalController;
+
     @VisibleForTesting
     final Map<Integer, MobileSignalController> mMobileSignalControllers =
             new HashMap<Integer, MobileSignalController>();
@@ -154,6 +158,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
         mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
                 mSignalsChangedCallbacks, mSignalClusters, this);
 
+        mEthernetSignalController = new EthernetSignalController(mContext, mSignalsChangedCallbacks,
+                mSignalClusters, this);
+
         // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
         updateAirplaneMode(true /* force callback */);
     }
@@ -281,6 +288,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
                 R.string.accessibility_airplane_mode);
         cluster.setNoSims(mHasNoSims);
         mWifiSignalController.notifyListeners();
+        mEthernetSignalController.notifyListeners();
         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
             mobileSignalController.notifyListeners();
         }
@@ -291,6 +299,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
         cb.onAirplaneModeChanged(mAirplaneMode);
         cb.onNoSimVisibleChanged(mHasNoSims);
         mWifiSignalController.notifyListeners();
+        mEthernetSignalController.notifyListeners();
         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
             mobileSignalController.notifyListeners();
         }
@@ -501,6 +510,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
             mobileSignalController.notifyListeners();
         }
         mWifiSignalController.notifyListeners();
+        mEthernetSignalController.notifyListeners();
     }
 
     /**
@@ -560,6 +570,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
         }
         mWifiSignalController.setInetCondition(
                 mValidatedTransports.get(mWifiSignalController.getTransportType()) ? 1 : 0);
+
+        mEthernetSignalController.setConnected(
+                mConnectedTransports.get(mEthernetSignalController.getTransportType()));
+        mEthernetSignalController.setInetCondition(
+                mValidatedTransports.get(mEthernetSignalController.getTransportType()) ? 1 : 0);
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -586,6 +601,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
         }
         mWifiSignalController.dump(pw);
 
+        mEthernetSignalController.dump(pw);
+
         mAccessPoints.dump(pw);
     }
 
@@ -731,6 +748,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
         void setSubs(List<SubscriptionInfo> subs);
         void setNoSims(boolean show);
 
+        void setEthernetIndicators(boolean visible, int icon, String contentDescription);
+
         void setIsAirplaneMode(boolean is, int airplaneIcon, int contentDescription);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java
new file mode 100644 (file)
index 0000000..82ced9f
--- /dev/null
@@ -0,0 +1,40 @@
+package com.android.systemui.statusbar.policy;
+
+import android.net.NetworkCapabilities;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+public class NetworkControllerEthernetTest extends NetworkControllerBaseTest {
+
+    public void testEthernetIcons() {
+        verifyLastEthernetIcon(false, 0);
+
+        setEthernetState(true, false);   // Connected, unvalidated.
+        verifyLastEthernetIcon(true, EthernetIcons.ETHERNET_ICONS[0][0]);
+
+        setEthernetState(true, true);    // Connected, validated.
+        verifyLastEthernetIcon(true, EthernetIcons.ETHERNET_ICONS[1][0]);
+
+        setEthernetState(true, false);   // Connected, unvalidated.
+        verifyLastEthernetIcon(true, EthernetIcons.ETHERNET_ICONS[0][0]);
+
+        setEthernetState(false, false);  // Disconnected.
+        verifyLastEthernetIcon(false, 0);
+    }
+
+    protected void setEthernetState(boolean connected, boolean validated) {
+        setConnectivity(validated ? 100 : 0, NetworkCapabilities.TRANSPORT_ETHERNET, connected);
+    }
+
+    protected void verifyLastEthernetIcon(boolean visible, int icon) {
+        ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class);
+
+        Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setEthernetIndicators(
+                visibleArg.capture(), iconArg.capture(),
+                ArgumentCaptor.forClass(String.class).capture());
+        assertEquals("Ethernet visible, in status bar", visible, (boolean) visibleArg.getValue());
+        assertEquals("Ethernet icon, in status bar", icon, (int) iconArg.getValue());
+    }
+}