Implement advanced icon style for output switch

This CL add new type "TYPE_ADVANCED" in AdaptiveOutlineDrawable.
It use to customize icon for output switch.

Bug: 157208551
Test: make -j42 RunSettingsLibRoboTests
Change-Id: I06bfacf2fc6e798648a94117d3e861a807650a5a
diff --git a/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml b/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml
index 76d106a..8f5b2ed 100644
--- a/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml
+++ b/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml
@@ -18,4 +18,8 @@
     <color name="homepage_generic_icon_background">#1A73E8</color>
 
     <color name="bt_outline_color">#1f000000</color> <!-- icon outline color -->
+
+    <color name="advanced_outline_color">#BDC1C6</color> <!-- icon outline color -->
+
+    <color name="advanced_icon_color">#3C4043</color>
 </resources>
diff --git a/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml b/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml
index 7f5b58c..8f6e358 100644
--- a/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml
+++ b/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml
@@ -18,6 +18,8 @@
 <resources>
     <!-- Dashboard foreground image inset (from background edge to foreground edge) -->
     <dimen name="dashboard_tile_foreground_image_inset">6dp</dimen>
+    <!-- Advanced dashboard foreground image inset (from background edge to foreground edge) -->
+    <dimen name="advanced_dashboard_tile_foreground_image_inset">9dp</dimen>
 
     <!-- Stroke size of adaptive outline -->
     <dimen name="adaptive_outline_stroke">1dp</dimen>
diff --git a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
index 1c65bc2..4438893 100644
--- a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
+++ b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
@@ -16,6 +16,10 @@
 
 package com.android.settingslib.widget;
 
+import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_ADVANCED;
+import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_DEFAULT;
+
+import android.annotation.ColorInt;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -27,35 +31,90 @@
 import android.graphics.drawable.DrawableWrapper;
 import android.util.PathParser;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Adaptive outline drawable with white plain background color and black outline
  */
 public class AdaptiveOutlineDrawable extends DrawableWrapper {
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({TYPE_DEFAULT, TYPE_ADVANCED})
+    public @interface AdaptiveOutlineIconType {
+        int TYPE_DEFAULT = 0;
+        int TYPE_ADVANCED = 1;
+    }
+
     @VisibleForTesting
-    final Paint mOutlinePaint;
+    Paint mOutlinePaint;
     private Path mPath;
-    private final int mInsetPx;
-    private final Bitmap mBitmap;
+    private int mInsetPx;
+    private int mStrokeWidth;
+    private Bitmap mBitmap;
+    private int mType;
 
     public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap) {
         super(new AdaptiveIconShapeDrawable(resources));
 
+        init(resources, bitmap, TYPE_DEFAULT);
+    }
+
+    public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap,
+            @AdaptiveOutlineIconType int type) {
+        super(new AdaptiveIconShapeDrawable(resources));
+
+        init(resources, bitmap, type);
+    }
+
+    private void init(Resources resources, Bitmap bitmap,
+            @AdaptiveOutlineIconType int type) {
+        mType = type;
         getDrawable().setTint(Color.WHITE);
         mPath = new Path(PathParser.createPathFromPathData(
                 resources.getString(com.android.internal.R.string.config_icon_mask)));
+        mStrokeWidth = resources.getDimensionPixelSize(R.dimen.adaptive_outline_stroke);
         mOutlinePaint = new Paint();
-        mOutlinePaint.setColor(resources.getColor(R.color.bt_outline_color, null));
+        mOutlinePaint.setColor(getColor(resources, type));
         mOutlinePaint.setStyle(Paint.Style.STROKE);
-        mOutlinePaint.setStrokeWidth(resources.getDimension(R.dimen.adaptive_outline_stroke));
+        mOutlinePaint.setStrokeWidth(mStrokeWidth);
         mOutlinePaint.setAntiAlias(true);
 
-        mInsetPx = resources
-                .getDimensionPixelSize(R.dimen.dashboard_tile_foreground_image_inset);
+        mInsetPx = getDimensionPixelSize(resources, type);
         mBitmap = bitmap;
     }
 
+    private @ColorInt int getColor(Resources resources, @AdaptiveOutlineIconType int type) {
+        int resId;
+        switch (type) {
+            case TYPE_ADVANCED:
+                resId = R.color.advanced_outline_color;
+                break;
+            case TYPE_DEFAULT:
+            default:
+                resId = R.color.bt_outline_color;
+                break;
+        }
+        return resources.getColor(resId, /* theme */ null);
+    }
+
+    private int getDimensionPixelSize(Resources resources, @AdaptiveOutlineIconType int type) {
+        int resId;
+        switch (type) {
+            case TYPE_ADVANCED:
+                resId = R.dimen.advanced_dashboard_tile_foreground_image_inset;
+                break;
+            case TYPE_DEFAULT:
+            default:
+                resId = R.dimen.dashboard_tile_foreground_image_inset;
+                break;
+        }
+        return resources.getDimensionPixelSize(resId);
+    }
+
     @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
@@ -68,7 +127,12 @@
         final int count = canvas.save();
         canvas.scale(scaleX, scaleY);
         // Draw outline
-        canvas.drawPath(mPath, mOutlinePaint);
+        if (mType == TYPE_DEFAULT) {
+            canvas.drawPath(mPath, mOutlinePaint);
+        } else {
+            canvas.drawCircle(2 * mInsetPx, 2 * mInsetPx, 2 * mInsetPx - mStrokeWidth,
+                    mOutlinePaint);
+        }
         canvas.restoreToCount(count);
 
         // Draw the foreground icon
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index a5ec5e6..e552d78 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -94,4 +94,7 @@
 
     <!-- Define minimal size of the tap area -->
     <dimen name="min_tap_target_size">48dp</dimen>
+
+    <!-- Size of advanced icon -->
+    <dimen name="advanced_icon_size">18dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 9d1b3cf..95e916b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -1,5 +1,7 @@
 package com.android.settingslib.bluetooth;
 
+import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_ADVANCED;
+
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
@@ -7,6 +9,7 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -213,6 +216,46 @@
     }
 
     /**
+     * Build device icon with advanced outline
+     */
+    public static Drawable buildAdvancedDrawable(Context context, Drawable drawable) {
+        final int iconSize = context.getResources().getDimensionPixelSize(
+                R.dimen.advanced_icon_size);
+        final Resources resources = context.getResources();
+
+        Bitmap bitmap = null;
+        if (drawable instanceof BitmapDrawable) {
+            bitmap = ((BitmapDrawable) drawable).getBitmap();
+        } else {
+            final int width = drawable.getIntrinsicWidth();
+            final int height = drawable.getIntrinsicHeight();
+            bitmap = createBitmap(drawable,
+                    width > 0 ? width : 1,
+                    height > 0 ? height : 1);
+        }
+
+        if (bitmap != null) {
+            final Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, iconSize,
+                    iconSize, false);
+            bitmap.recycle();
+            return new AdaptiveOutlineDrawable(resources, resizedBitmap, TYPE_ADVANCED);
+        }
+
+        return drawable;
+    }
+
+    /**
+     * Creates a drawable with specified width and height.
+     */
+    public static Bitmap createBitmap(Drawable drawable, int width, int height) {
+        final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(bitmap);
+        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        drawable.draw(canvas);
+        return bitmap;
+    }
+
+    /**
      * Get boolean Bluetooth metadata
      *
      * @param bluetoothDevice the BluetoothDevice to get metadata
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 40d8048..00f94f5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -21,7 +21,6 @@
 import android.graphics.drawable.Drawable;
 import android.media.MediaRoute2Info;
 import android.media.MediaRouter2Manager;
-import android.util.Pair;
 
 import com.android.settingslib.R;
 import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -57,13 +56,11 @@
 
     @Override
     public Drawable getIcon() {
-        final Pair<Drawable, String> pair = BluetoothUtils
-                .getBtRainbowDrawableWithDescription(mContext, mCachedDevice);
-        return isFastPairDevice()
-                ? pair.first
-                : BluetoothUtils.buildBtRainbowDrawable(mContext,
-                        mContext.getDrawable(R.drawable.ic_headphone),
-                        mCachedDevice.getAddress().hashCode());
+        final Drawable drawable = getIconWithoutBackground();
+        if (!isFastPairDevice()) {
+            setColorFilter(drawable);
+        }
+        return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 8d6bc5c..ea71e52 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -55,9 +55,9 @@
 
     @Override
     public Drawable getIcon() {
-        //TODO(b/120669861): Return remote device icon uri once api is ready.
-        return BluetoothUtils.buildBtRainbowDrawable(mContext,
-                mContext.getDrawable(getDrawableResId()), getId().hashCode());
+        final Drawable drawable = getIconWithoutBackground();
+        setColorFilter(drawable);
+        return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 317077b..126f9b9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -31,6 +31,9 @@
 import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
 import android.media.MediaRoute2Info;
 import android.media.MediaRouter2Manager;
@@ -39,6 +42,8 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.settingslib.R;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -131,6 +136,14 @@
                 getId());
     }
 
+    void setColorFilter(Drawable drawable) {
+        final ColorStateList list =
+                mContext.getResources().getColorStateList(
+                        R.color.advanced_icon_color, mContext.getTheme());
+        drawable.setColorFilter(new PorterDuffColorFilter(list.getDefaultColor(),
+                PorterDuff.Mode.SRC_IN));
+    }
+
     /**
      * Get name from MediaDevice.
      *
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index c43a512..b6c0b30 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -85,8 +85,9 @@
 
     @Override
     public Drawable getIcon() {
-        return BluetoothUtils.buildBtRainbowDrawable(mContext,
-                mContext.getDrawable(getDrawableResId()), getId().hashCode());
+        final Drawable drawable = getIconWithoutBackground();
+        setColorFilter(drawable);
+        return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
     }
 
     @Override
@@ -105,7 +106,7 @@
             case TYPE_HDMI:
             case TYPE_WIRED_HEADSET:
             case TYPE_WIRED_HEADPHONES:
-                resId = com.android.internal.R.drawable.ic_bt_headphones_a2dp;
+                resId = R.drawable.ic_headphone;
                 break;
             case TYPE_BUILTIN_SPEAKER:
             default:
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 421e5c0..00d1f76 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -79,13 +79,11 @@
     public void getDrawableResId_returnCorrectResId() {
         when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES);
 
-        assertThat(mPhoneMediaDevice.getDrawableResId())
-                .isEqualTo(com.android.internal.R.drawable.ic_bt_headphones_a2dp);
+        assertThat(mPhoneMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_headphone);
 
         when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADSET);
 
-        assertThat(mPhoneMediaDevice.getDrawableResId())
-                .isEqualTo(com.android.internal.R.drawable.ic_bt_headphones_a2dp);
+        assertThat(mPhoneMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_headphone);
 
         when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);