diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index 7ab18a4407d..3424e7644b9 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -1533,6 +1533,22 @@
column="5"/>
+
+
+
+
#fdcfe8
#e9d2fd
#cbf0f8
+
+ #1f000000
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 248fb818031..4a65bc9f8c9 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -404,4 +404,13 @@
48dp
+
+
+ 24dp
+
+
+ 1dp
+
+
+ 4dp
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
index 38603526ba6..fe73a2ecc8b 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
@@ -80,8 +80,10 @@ public class BluetoothDetailsHeaderController extends BluetoothDetailsController
@Override
protected void refresh() {
- setHeaderProperties();
- mHeaderController.done(mFragment.getActivity(), true /* rebindActions */);
+ if (isAvailable()) {
+ setHeaderProperties();
+ mHeaderController.done(mFragment.getActivity(), true /* rebindActions */);
+ }
}
@Override
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
index 8d727ebdb96..4a7ca27c178 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
@@ -164,6 +164,8 @@ public final class BluetoothDevicePreference extends GearPreference implements
final ImageView imageView = (ImageView) view.findViewById(android.R.id.icon);
if (imageView != null) {
imageView.setContentDescription(contentDescription);
+ imageView.setElevation(
+ getContext().getResources().getDimension(R.dimen.bt_icon_elevation));
}
super.onBindViewHolder(view);
}
diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java
index e02ddc42616..ecf40b61074 100755
--- a/src/com/android/settings/bluetooth/Utils.java
+++ b/src/com/android/settings/bluetooth/Utils.java
@@ -22,8 +22,11 @@ import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
+import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.MediaStore;
import android.provider.Settings;
import android.util.Log;
import android.util.Pair;
@@ -33,14 +36,18 @@ import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import com.android.settings.R;
+import com.android.settings.homepage.AdaptiveIconShapeDrawable;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.AdaptiveIcon;
+import com.android.settings.widget.AdaptiveOutlineDrawable;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.BluetoothUtils.ErrorListener;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
+import java.io.IOException;
+
/**
* Utils is a helper class that contains constants for various
* Android resource IDs, debug logging flags, and static methods
@@ -165,6 +172,7 @@ public final class Utils {
if (bluetoothDevice == null) {
return false;
}
+
return Boolean.parseBoolean(bluetoothDevice.getMetadata(key));
}
@@ -193,7 +201,36 @@ public final class Utils {
CachedBluetoothDevice cachedDevice) {
final Pair pair = BluetoothUtils.getBtClassDrawableWithDescription(
context, cachedDevice);
+ final boolean untetheredHeadset = Utils.getBooleanMetaData(cachedDevice.getDevice(),
+ BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET);
+ final int iconSize = context.getResources().getDimensionPixelSize(
+ R.dimen.bt_nearby_icon_size);
final Resources resources = context.getResources();
+
+ // Deal with untethered headset
+ if (untetheredHeadset) {
+ final String uriString = Utils.getStringMetaData(cachedDevice.getDevice(),
+ BluetoothDevice.METADATA_MAIN_ICON);
+ final Uri iconUri = uriString != null ? Uri.parse(uriString) : null;
+ if (iconUri != null) {
+ try {
+ final Bitmap bitmap = MediaStore.Images.Media.getBitmap(
+ context.getContentResolver(), iconUri);
+ if (bitmap != null) {
+ final Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, iconSize,
+ iconSize, false);
+ bitmap.recycle();
+ final AdaptiveOutlineDrawable drawable = new AdaptiveOutlineDrawable(
+ resources, resizedBitmap);
+ return new Pair<>(drawable, pair.second);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to get drawable for: " + iconUri, e);
+ }
+ }
+ }
+
+ // Deal with normal headset
final int[] iconFgColors = resources.getIntArray(R.array.bt_icon_fg_colors);
final int[] iconBgColors = resources.getIntArray(R.array.bt_icon_bg_colors);
diff --git a/src/com/android/settings/widget/AdaptiveOutlineDrawable.java b/src/com/android/settings/widget/AdaptiveOutlineDrawable.java
new file mode 100644
index 00000000000..84c4e2f3844
--- /dev/null
+++ b/src/com/android/settings/widget/AdaptiveOutlineDrawable.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 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.settings.widget;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.DrawableWrapper;
+import android.util.PathParser;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.homepage.AdaptiveIconShapeDrawable;
+
+/**
+ * Adaptive outline drawable with white plain background color and black outline
+ */
+public class AdaptiveOutlineDrawable extends DrawableWrapper {
+ @VisibleForTesting
+ final Paint mOutlinePaint;
+ private Path mPath;
+ private final int mInsetPx;
+ private final Bitmap mBitmap;
+
+ public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap) {
+ super(new AdaptiveIconShapeDrawable(resources));
+
+ getDrawable().setTint(Color.WHITE);
+ mPath = new Path(PathParser.createPathFromPathData(
+ resources.getString(com.android.internal.R.string.config_icon_mask)));
+ mOutlinePaint = new Paint();
+ mOutlinePaint.setColor(resources.getColor(R.color.bt_outline_color, null));
+ mOutlinePaint.setStyle(Paint.Style.STROKE);
+ mOutlinePaint.setStrokeWidth(resources.getDimension(R.dimen.adaptive_outline_stroke));
+ mOutlinePaint.setAntiAlias(true);
+
+ mInsetPx = resources
+ .getDimensionPixelSize(R.dimen.dashboard_tile_foreground_image_inset);
+ mBitmap = bitmap;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ final Rect bounds = getBounds();
+ final float pathSize = AdaptiveIconDrawable.MASK_SIZE;
+
+ final float scaleX = (bounds.right - bounds.left) / pathSize;
+ final float scaleY = (bounds.bottom - bounds.top) / pathSize;
+
+ final int count = canvas.save();
+ canvas.scale(scaleX, scaleY);
+ // Draw outline
+ canvas.drawPath(mPath, mOutlinePaint);
+ canvas.restoreToCount(count);
+
+ // Draw the foreground icon
+ canvas.drawBitmap(mBitmap, bounds.left + mInsetPx, bounds.top + mInsetPx, null);
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mBitmap.getHeight() + 2 * mInsetPx;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mBitmap.getWidth() + 2 * mInsetPx;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
index 51e559f8900..a956518e898 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
@@ -29,6 +29,8 @@ import android.content.Context;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.widget.AdaptiveIcon;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -39,6 +41,7 @@ import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class UtilsTest {
@@ -51,6 +54,8 @@ public class UtilsTest {
private Context mContext;
@Mock
private BluetoothDevice mBluetoothDevice;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
private MetricsFeatureProvider mMetricsFeatureProvider;
@@ -107,4 +112,16 @@ public class UtilsTest {
BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).isEqualTo(true);
}
+ @Test
+ public void getBtRainbowDrawableWithDescription_normalHeadset_returnAdaptiveIcon() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn("false");
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+ when(mCachedBluetoothDevice.getAddress()).thenReturn("1f:aa:bb");
+
+ assertThat(Utils.getBtRainbowDrawableWithDescription(RuntimeEnvironment.application,
+ mCachedBluetoothDevice).first).isInstanceOf(
+ AdaptiveIcon.class);
+ }
+
}
diff --git a/tests/robotests/src/com/android/settings/widget/AdaptiveOutlineDrawableTest.java b/tests/robotests/src/com/android/settings/widget/AdaptiveOutlineDrawableTest.java
new file mode 100644
index 00000000000..f21fc34e2a8
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/widget/AdaptiveOutlineDrawableTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 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.settings.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.res.Resources;
+import android.graphics.Paint;
+
+import com.android.settings.R;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class AdaptiveOutlineDrawableTest {
+
+ @Test
+ public void constructor_initPaint() {
+ final Resources resources = RuntimeEnvironment.application.getResources();
+ final AdaptiveOutlineDrawable drawable = new AdaptiveOutlineDrawable(resources, null);
+
+ assertThat(drawable.mOutlinePaint.getStyle()).isEqualTo(Paint.Style.STROKE);
+ assertThat(drawable.mOutlinePaint.getStrokeWidth()).isWithin(0.01f).of(
+ resources.getDimension(R.dimen.adaptive_outline_stroke));
+ }
+
+}