Merge "Implement advanced icon style for output switch" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
202425a4f7
@@ -18,4 +18,8 @@
|
|||||||
<color name="homepage_generic_icon_background">#1A73E8</color>
|
<color name="homepage_generic_icon_background">#1A73E8</color>
|
||||||
|
|
||||||
<color name="bt_outline_color">#1f000000</color> <!-- icon outline 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>
|
</resources>
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<!-- Dashboard foreground image inset (from background edge to foreground edge) -->
|
<!-- Dashboard foreground image inset (from background edge to foreground edge) -->
|
||||||
<dimen name="dashboard_tile_foreground_image_inset">6dp</dimen>
|
<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 -->
|
<!-- Stroke size of adaptive outline -->
|
||||||
<dimen name="adaptive_outline_stroke">1dp</dimen>
|
<dimen name="adaptive_outline_stroke">1dp</dimen>
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
package com.android.settingslib.widget;
|
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.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
@@ -27,35 +31,90 @@ import android.graphics.drawable.AdaptiveIconDrawable;
|
|||||||
import android.graphics.drawable.DrawableWrapper;
|
import android.graphics.drawable.DrawableWrapper;
|
||||||
import android.util.PathParser;
|
import android.util.PathParser;
|
||||||
|
|
||||||
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.VisibleForTesting;
|
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
|
* Adaptive outline drawable with white plain background color and black outline
|
||||||
*/
|
*/
|
||||||
public class AdaptiveOutlineDrawable extends DrawableWrapper {
|
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
|
@VisibleForTesting
|
||||||
final Paint mOutlinePaint;
|
Paint mOutlinePaint;
|
||||||
private Path mPath;
|
private Path mPath;
|
||||||
private final int mInsetPx;
|
private int mInsetPx;
|
||||||
private final Bitmap mBitmap;
|
private int mStrokeWidth;
|
||||||
|
private Bitmap mBitmap;
|
||||||
|
private int mType;
|
||||||
|
|
||||||
public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap) {
|
public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap) {
|
||||||
super(new AdaptiveIconShapeDrawable(resources));
|
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);
|
getDrawable().setTint(Color.WHITE);
|
||||||
mPath = new Path(PathParser.createPathFromPathData(
|
mPath = new Path(PathParser.createPathFromPathData(
|
||||||
resources.getString(com.android.internal.R.string.config_icon_mask)));
|
resources.getString(com.android.internal.R.string.config_icon_mask)));
|
||||||
|
mStrokeWidth = resources.getDimensionPixelSize(R.dimen.adaptive_outline_stroke);
|
||||||
mOutlinePaint = new Paint();
|
mOutlinePaint = new Paint();
|
||||||
mOutlinePaint.setColor(resources.getColor(R.color.bt_outline_color, null));
|
mOutlinePaint.setColor(getColor(resources, type));
|
||||||
mOutlinePaint.setStyle(Paint.Style.STROKE);
|
mOutlinePaint.setStyle(Paint.Style.STROKE);
|
||||||
mOutlinePaint.setStrokeWidth(resources.getDimension(R.dimen.adaptive_outline_stroke));
|
mOutlinePaint.setStrokeWidth(mStrokeWidth);
|
||||||
mOutlinePaint.setAntiAlias(true);
|
mOutlinePaint.setAntiAlias(true);
|
||||||
|
|
||||||
mInsetPx = resources
|
mInsetPx = getDimensionPixelSize(resources, type);
|
||||||
.getDimensionPixelSize(R.dimen.dashboard_tile_foreground_image_inset);
|
|
||||||
mBitmap = bitmap;
|
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
|
@Override
|
||||||
public void draw(Canvas canvas) {
|
public void draw(Canvas canvas) {
|
||||||
super.draw(canvas);
|
super.draw(canvas);
|
||||||
@@ -68,7 +127,12 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
|
|||||||
final int count = canvas.save();
|
final int count = canvas.save();
|
||||||
canvas.scale(scaleX, scaleY);
|
canvas.scale(scaleX, scaleY);
|
||||||
// Draw outline
|
// 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);
|
canvas.restoreToCount(count);
|
||||||
|
|
||||||
// Draw the foreground icon
|
// Draw the foreground icon
|
||||||
|
|||||||
@@ -94,4 +94,7 @@
|
|||||||
|
|
||||||
<!-- Define minimal size of the tap area -->
|
<!-- Define minimal size of the tap area -->
|
||||||
<dimen name="min_tap_target_size">48dp</dimen>
|
<dimen name="min_tap_target_size">48dp</dimen>
|
||||||
|
|
||||||
|
<!-- Size of advanced icon -->
|
||||||
|
<dimen name="advanced_icon_size">18dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.android.settingslib.bluetooth;
|
package com.android.settingslib.bluetooth;
|
||||||
|
|
||||||
|
import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_ADVANCED;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothClass;
|
import android.bluetooth.BluetoothClass;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
@@ -7,6 +9,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -212,6 +215,46 @@ public class BluetoothUtils {
|
|||||||
return new Pair<>(pair.first, pair.second);
|
return new Pair<>(pair.first, pair.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Get boolean Bluetooth metadata
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import android.content.Context;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.media.MediaRoute2Info;
|
import android.media.MediaRoute2Info;
|
||||||
import android.media.MediaRouter2Manager;
|
import android.media.MediaRouter2Manager;
|
||||||
import android.util.Pair;
|
|
||||||
|
|
||||||
import com.android.settingslib.R;
|
import com.android.settingslib.R;
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
@@ -57,13 +56,11 @@ public class BluetoothMediaDevice extends MediaDevice {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Drawable getIcon() {
|
public Drawable getIcon() {
|
||||||
final Pair<Drawable, String> pair = BluetoothUtils
|
final Drawable drawable = getIconWithoutBackground();
|
||||||
.getBtRainbowDrawableWithDescription(mContext, mCachedDevice);
|
if (!isFastPairDevice()) {
|
||||||
return isFastPairDevice()
|
setColorFilter(drawable);
|
||||||
? pair.first
|
}
|
||||||
: BluetoothUtils.buildBtRainbowDrawable(mContext,
|
return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
|
||||||
mContext.getDrawable(R.drawable.ic_headphone),
|
|
||||||
mCachedDevice.getAddress().hashCode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -55,9 +55,9 @@ public class InfoMediaDevice extends MediaDevice {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Drawable getIcon() {
|
public Drawable getIcon() {
|
||||||
//TODO(b/120669861): Return remote device icon uri once api is ready.
|
final Drawable drawable = getIconWithoutBackground();
|
||||||
return BluetoothUtils.buildBtRainbowDrawable(mContext,
|
setColorFilter(drawable);
|
||||||
mContext.getDrawable(getDrawableResId()), getId().hashCode());
|
return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
|
|||||||
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
|
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.PorterDuffColorFilter;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.media.MediaRoute2Info;
|
import android.media.MediaRoute2Info;
|
||||||
import android.media.MediaRouter2Manager;
|
import android.media.MediaRouter2Manager;
|
||||||
@@ -39,6 +42,8 @@ import android.text.TextUtils;
|
|||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import com.android.settingslib.R;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
@@ -131,6 +136,14 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
|
|||||||
getId());
|
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.
|
* Get name from MediaDevice.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -85,8 +85,9 @@ public class PhoneMediaDevice extends MediaDevice {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Drawable getIcon() {
|
public Drawable getIcon() {
|
||||||
return BluetoothUtils.buildBtRainbowDrawable(mContext,
|
final Drawable drawable = getIconWithoutBackground();
|
||||||
mContext.getDrawable(getDrawableResId()), getId().hashCode());
|
setColorFilter(drawable);
|
||||||
|
return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -105,7 +106,7 @@ public class PhoneMediaDevice extends MediaDevice {
|
|||||||
case TYPE_HDMI:
|
case TYPE_HDMI:
|
||||||
case TYPE_WIRED_HEADSET:
|
case TYPE_WIRED_HEADSET:
|
||||||
case TYPE_WIRED_HEADPHONES:
|
case TYPE_WIRED_HEADPHONES:
|
||||||
resId = com.android.internal.R.drawable.ic_bt_headphones_a2dp;
|
resId = R.drawable.ic_headphone;
|
||||||
break;
|
break;
|
||||||
case TYPE_BUILTIN_SPEAKER:
|
case TYPE_BUILTIN_SPEAKER:
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -79,13 +79,11 @@ public class PhoneMediaDeviceTest {
|
|||||||
public void getDrawableResId_returnCorrectResId() {
|
public void getDrawableResId_returnCorrectResId() {
|
||||||
when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES);
|
when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES);
|
||||||
|
|
||||||
assertThat(mPhoneMediaDevice.getDrawableResId())
|
assertThat(mPhoneMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_headphone);
|
||||||
.isEqualTo(com.android.internal.R.drawable.ic_bt_headphones_a2dp);
|
|
||||||
|
|
||||||
when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADSET);
|
when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADSET);
|
||||||
|
|
||||||
assertThat(mPhoneMediaDevice.getDrawableResId())
|
assertThat(mPhoneMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_headphone);
|
||||||
.isEqualTo(com.android.internal.R.drawable.ic_bt_headphones_a2dp);
|
|
||||||
|
|
||||||
when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
|
when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user