Add battery indicator to bluetooth icon

This cl change util method in bluetooth package to return
drawable instead of resId.

If the bt device has battery level, then method return customized
layerDrawable, otherwise return a simple drawable created from
resId.

Bug: 63393322
Test: RunSettingsRoboTests

Change-Id: Ib21822eafda0e8570212ce5cb070478e4f4876a2
diff --git a/res/layout-sw320dp/settings_entity_header.xml b/res/layout-sw320dp/settings_entity_header.xml
index 5cedd8d..951961c 100644
--- a/res/layout-sw320dp/settings_entity_header.xml
+++ b/res/layout-sw320dp/settings_entity_header.xml
@@ -38,7 +38,7 @@
             android:id="@+id/entity_header_icon"
             android:layout_width="48dp"
             android:layout_height="48dp"
-            android:scaleType="fitXY"
+            android:scaleType="fitCenter"
             android:layout_gravity="center_horizontal"
             android:antialias="true" />
 
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
index 5ec7c85..1470214 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
@@ -16,8 +16,8 @@
 
 package com.android.settings.bluetooth;
 
-
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.support.v14.preference.PreferenceFragment;
 import android.support.v7.preference.PreferenceScreen;
 import android.util.Pair;
@@ -51,11 +51,11 @@
     }
 
     protected void setHeaderProperties() {
-        Pair<Integer, String> pair = Utils.getBtClassDrawableWithDescription
-                (mContext.getResources(), mCachedDevice);
+        final Pair<Drawable, String> pair = Utils.getBtClassDrawableWithDescription
+                (mContext, mCachedDevice);
         String summaryText = mCachedDevice.getConnectionSummary();
         mHeaderController.setLabel(mCachedDevice.getName());
-        mHeaderController.setIcon(mContext.getDrawable(pair.first));
+        mHeaderController.setIcon(pair.first);
         mHeaderController.setIconContentDescription(pair.second);
         mHeaderController.setSummary(summaryText);
     }
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
index a216400..7b81018 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.os.UserManager;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceViewHolder;
@@ -120,9 +121,9 @@
         // Null check is done at the framework
         setSummary(mCachedDevice.getConnectionSummary());
 
-        Pair<Integer, String> pair = Utils.getBtClassDrawableWithDescription(mResources,
+        final Pair<Drawable, String> pair = Utils.getBtClassDrawableWithDescription(getContext(),
                 mCachedDevice);
-        if (pair.first != 0) {
+        if (pair.first != null) {
             setIcon(pair.first);
             contentDescription = pair.second;
         }
diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java
index 26edd84..e80237eb 100755
--- a/src/com/android/settings/bluetooth/Utils.java
+++ b/src/com/android/settings/bluetooth/Utils.java
@@ -23,6 +23,9 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.IdRes;
 import android.support.annotation.VisibleForTesting;
 import android.util.Pair;
 import android.widget.Toast;
@@ -36,6 +39,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
 import com.android.settingslib.bluetooth.LocalBluetoothProfile;
 import com.android.settingslib.bluetooth.Utils.ErrorListener;
+import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
 
 import java.util.List;
 
@@ -150,27 +154,31 @@
         }
     };
 
-    static Pair<Integer, String> getBtClassDrawableWithDescription(Resources r,
+    static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context,
             CachedBluetoothDevice cachedDevice) {
         BluetoothClass btClass = cachedDevice.getBtClass();
+        final int level = cachedDevice.getBatteryLevel();
         if (btClass != null) {
             switch (btClass.getMajorDeviceClass()) {
                 case BluetoothClass.Device.Major.COMPUTER:
-                    return new Pair<Integer, String>(R.drawable.ic_bt_laptop,
-                           r.getString(R.string.bluetooth_talkback_computer));
+                    return new Pair<>(getBluetoothDrawable(context, R.drawable.ic_bt_laptop, level),
+                            context.getString(R.string.bluetooth_talkback_computer));
 
                 case BluetoothClass.Device.Major.PHONE:
-                    return new Pair<Integer, String>(R.drawable.ic_bt_cellphone,
-                            r.getString(R.string.bluetooth_talkback_phone));
+                    return new Pair<>(
+                            getBluetoothDrawable(context, R.drawable.ic_bt_cellphone, level),
+                            context.getString(R.string.bluetooth_talkback_phone));
 
                 case BluetoothClass.Device.Major.PERIPHERAL:
-                    return new Pair<Integer, String>(HidProfile.getHidClassDrawable(btClass),
-                            r.getString(
-                                    R.string.bluetooth_talkback_input_peripheral));
+                    return new Pair<>(
+                            getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass),
+                                    level),
+                            context.getString(R.string.bluetooth_talkback_input_peripheral));
 
                 case BluetoothClass.Device.Major.IMAGING:
-                    return new Pair<Integer, String>(R.drawable.ic_settings_print,
-                            r.getString(R.string.bluetooth_talkback_imaging));
+                    return new Pair<>(
+                            getBluetoothDrawable(context, R.drawable.ic_settings_print, level),
+                            context.getString(R.string.bluetooth_talkback_imaging));
 
                 default:
                     // unrecognized device class; continue
@@ -181,20 +189,34 @@
         for (LocalBluetoothProfile profile : profiles) {
             int resId = profile.getDrawableResource(btClass);
             if (resId != 0) {
-                return new Pair<Integer, String>(resId, null);
+                return new Pair<>(getBluetoothDrawable(context, resId, level), null);
             }
         }
         if (btClass != null) {
             if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
-                return new Pair<Integer, String>(R.drawable.ic_bt_headset_hfp,
-                        r.getString(R.string.bluetooth_talkback_headset));
+                return new Pair<>(
+                        getBluetoothDrawable(context, R.drawable.ic_bt_headset_hfp, level),
+                        context.getString(R.string.bluetooth_talkback_headset));
             }
             if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
-                return new Pair<Integer, String>(R.drawable.ic_bt_headphones_a2dp,
-                        r.getString(R.string.bluetooth_talkback_headphone));
+                return new Pair<>(
+                        getBluetoothDrawable(context, R.drawable.ic_bt_headphones_a2dp, level),
+                        context.getString(R.string.bluetooth_talkback_headphone));
             }
         }
-        return new Pair<Integer, String>(R.drawable.ic_settings_bluetooth,
-                r.getString(R.string.bluetooth_talkback_bluetooth));
+        return new Pair<>(getBluetoothDrawable(context, R.drawable.ic_settings_bluetooth, level),
+                context.getString(R.string.bluetooth_talkback_bluetooth));
+    }
+
+    @VisibleForTesting
+    static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId,
+            int batteryLevel) {
+        if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+            return BluetoothDeviceLayerDrawable.createLayerDrawable(context, resId, batteryLevel);
+        } else if (resId != 0) {
+            return context.getDrawable(resId);
+        } else {
+            return null;
+        }
     }
 }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java
index 27c1a83..98a3580 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java
@@ -32,6 +32,7 @@
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.shadow.SettingsShadowBluetoothDevice;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
 import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
 import com.android.settings.widget.EntityHeaderController;
 
@@ -45,7 +46,8 @@
 
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
-        shadows={SettingsShadowBluetoothDevice.class, ShadowEntityHeaderController.class})
+        shadows={SettingsShadowBluetoothDevice.class, ShadowEntityHeaderController.class,
+                SettingsShadowResources.class})
 public class BluetoothDetailsHeaderControllerTest extends BluetoothDetailsControllerTestBase {
     private BluetoothDetailsHeaderController mController;
     private LayoutPreference mPreference;
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java
index d60571c..b16e5bc 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java
@@ -26,6 +26,7 @@
 import com.android.settings.TestConfig;
 import com.android.settings.core.instrumentation.MetricsFeatureProvider;
 import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
 import org.junit.Before;
@@ -44,7 +45,8 @@
 import static org.mockito.Mockito.when;
 
 @RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
+        shadows = SettingsShadowResources.class)
 public class BluetoothDevicePreferenceTest {
 
     private Context mContext;
@@ -140,8 +142,11 @@
 
     @Test
     public void imagingDeviceIcon_isICSettingsPrint() {
+        when(mCachedBluetoothDevice.getBatteryLevel()).thenReturn(
+                BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
         when(mCachedBluetoothDevice.getBtClass()).thenReturn(
                 new BluetoothClass(BluetoothClass.Device.Major.IMAGING));
+
         mPreference.onDeviceAttributesChanged();
         assertThat(mPreference.getIcon()).isEqualTo(
                 mContext.getDrawable(R.drawable.ic_settings_print));
diff --git a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
index 4667dac..7654921 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
@@ -15,14 +15,21 @@
  */
 package com.android.settings.bluetooth;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothDevice;
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
 import com.android.settings.core.instrumentation.MetricsFeatureProvider;
 import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -30,6 +37,7 @@
 import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
 import static org.mockito.Matchers.anyInt;
@@ -40,7 +48,8 @@
 import static org.mockito.Mockito.when;
 
 @RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
+        shadows = SettingsShadowResources.class)
 public class UtilsTest {
 
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -60,11 +69,27 @@
     }
 
     @Test
-    public void showConnectingError_shouldLogBluetoothConnectError() {
+    public void testShowConnectingError_shouldLogBluetoothConnectError() {
         when(mContext.getString(anyInt(), anyString())).thenReturn("testMessage");
         Utils.showConnectingError(mContext, "testName", mock(LocalBluetoothManager.class));
 
         verify(mMetricsFeatureProvider).visible(eq(mContext), anyInt(),
-            eq(MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR));
+                eq(MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR));
+    }
+
+    @Test
+    public void testGetBluetoothDrawable_noBatteryLevel_returnSimpleDrawable() {
+        final Drawable drawable = Utils.getBluetoothDrawable(RuntimeEnvironment.application,
+                R.drawable.ic_bt_laptop, BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+
+        assertThat(drawable).isNotInstanceOf(BluetoothDeviceLayerDrawable.class);
+    }
+
+    @Test
+    public void testGetBluetoothDrawable_hasBatteryLevel_returnLayerDrawable() {
+        final Drawable drawable = Utils.getBluetoothDrawable(RuntimeEnvironment.application,
+                R.drawable.ic_bt_laptop, 10 /* batteryLevel */);
+
+        assertThat(drawable).isInstanceOf(BluetoothDeviceLayerDrawable.class);
     }
 }