From 36ce63dcb549d878a8df09d18c65e24545b1595b Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Tue, 19 Mar 2019 10:18:19 -0700 Subject: [PATCH] Add fp icon with background shape Fixes: 126425211 Test: RunSettingsRoboTests Change-Id: I779f76f597b80d73b6dd6eb9e43a96abc9fee0bb --- color-check-baseline.xml | 16 ++++ res/values/colors.xml | 2 + res/values/dimens.xml | 9 ++ .../BluetoothDetailsHeaderController.java | 6 +- .../bluetooth/BluetoothDevicePreference.java | 2 + src/com/android/settings/bluetooth/Utils.java | 37 ++++++++ .../widget/AdaptiveOutlineDrawable.java | 90 +++++++++++++++++++ .../android/settings/bluetooth/UtilsTest.java | 17 ++++ .../widget/AdaptiveOutlineDrawableTest.java | 44 +++++++++ 9 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 src/com/android/settings/widget/AdaptiveOutlineDrawable.java create mode 100644 tests/robotests/src/com/android/settings/widget/AdaptiveOutlineDrawableTest.java 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)); + } + +}