Add fp icon with background shape
Fixes: 126425211 Test: RunSettingsRoboTests Change-Id: I779f76f597b80d73b6dd6eb9e43a96abc9fee0bb
This commit is contained in:
@@ -1533,6 +1533,22 @@
|
|||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
<issue
|
||||||
|
id="HardCodedColor"
|
||||||
|
severity="Error"
|
||||||
|
message="Avoid using hardcoded color"
|
||||||
|
category="Correctness"
|
||||||
|
priority="4"
|
||||||
|
summary="Using hardcoded color"
|
||||||
|
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
|
||||||
|
errorLine1=" <color name="bt_outline_color">#1f000000</color> <!-- icon outline color -->"
|
||||||
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
|
<location
|
||||||
|
file="res/values/colors.xml"
|
||||||
|
line="160"
|
||||||
|
column="5"/>
|
||||||
|
</issue>
|
||||||
|
|
||||||
<issue
|
<issue
|
||||||
id="HardCodedColor"
|
id="HardCodedColor"
|
||||||
severity="Error"
|
severity="Error"
|
||||||
|
@@ -156,4 +156,6 @@
|
|||||||
<color name="bt_color_bg_5">#fdcfe8</color> <!-- Material Pink 100 -->
|
<color name="bt_color_bg_5">#fdcfe8</color> <!-- Material Pink 100 -->
|
||||||
<color name="bt_color_bg_6">#e9d2fd</color> <!-- Material Purple 100 -->
|
<color name="bt_color_bg_6">#e9d2fd</color> <!-- Material Purple 100 -->
|
||||||
<color name="bt_color_bg_7">#cbf0f8</color> <!-- Material Cyan 100 -->
|
<color name="bt_color_bg_7">#cbf0f8</color> <!-- Material Cyan 100 -->
|
||||||
|
|
||||||
|
<color name="bt_outline_color">#1f000000</color> <!-- icon outline color -->
|
||||||
</resources>
|
</resources>
|
@@ -404,4 +404,13 @@
|
|||||||
|
|
||||||
<!-- Wi-Fi DPP fragment icon size -->
|
<!-- Wi-Fi DPP fragment icon size -->
|
||||||
<dimen name="wifi_dpp_fragment_icon_width_height">48dp</dimen>
|
<dimen name="wifi_dpp_fragment_icon_width_height">48dp</dimen>
|
||||||
|
|
||||||
|
<!-- Size of nearby icon -->
|
||||||
|
<dimen name="bt_nearby_icon_size">24dp</dimen>
|
||||||
|
|
||||||
|
<!-- Stroke size of adaptive outline -->
|
||||||
|
<dimen name="adaptive_outline_stroke">1dp</dimen>
|
||||||
|
|
||||||
|
<!-- Elevation of bluetooth icon -->
|
||||||
|
<dimen name="bt_icon_elevation">4dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -80,9 +80,11 @@ public class BluetoothDetailsHeaderController extends BluetoothDetailsController
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void refresh() {
|
protected void refresh() {
|
||||||
|
if (isAvailable()) {
|
||||||
setHeaderProperties();
|
setHeaderProperties();
|
||||||
mHeaderController.done(mFragment.getActivity(), true /* rebindActions */);
|
mHeaderController.done(mFragment.getActivity(), true /* rebindActions */);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPreferenceKey() {
|
public String getPreferenceKey() {
|
||||||
|
@@ -164,6 +164,8 @@ public final class BluetoothDevicePreference extends GearPreference implements
|
|||||||
final ImageView imageView = (ImageView) view.findViewById(android.R.id.icon);
|
final ImageView imageView = (ImageView) view.findViewById(android.R.id.icon);
|
||||||
if (imageView != null) {
|
if (imageView != null) {
|
||||||
imageView.setContentDescription(contentDescription);
|
imageView.setContentDescription(contentDescription);
|
||||||
|
imageView.setElevation(
|
||||||
|
getContext().getResources().getDimension(R.dimen.bt_icon_elevation));
|
||||||
}
|
}
|
||||||
super.onBindViewHolder(view);
|
super.onBindViewHolder(view);
|
||||||
}
|
}
|
||||||
|
@@ -22,8 +22,11 @@ import android.bluetooth.BluetoothProfile;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.MediaStore;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@@ -33,14 +36,18 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.homepage.AdaptiveIconShapeDrawable;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.widget.AdaptiveIcon;
|
import com.android.settings.widget.AdaptiveIcon;
|
||||||
|
import com.android.settings.widget.AdaptiveOutlineDrawable;
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils.ErrorListener;
|
import com.android.settingslib.bluetooth.BluetoothUtils.ErrorListener;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utils is a helper class that contains constants for various
|
* Utils is a helper class that contains constants for various
|
||||||
* Android resource IDs, debug logging flags, and static methods
|
* Android resource IDs, debug logging flags, and static methods
|
||||||
@@ -165,6 +172,7 @@ public final class Utils {
|
|||||||
if (bluetoothDevice == null) {
|
if (bluetoothDevice == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Boolean.parseBoolean(bluetoothDevice.getMetadata(key));
|
return Boolean.parseBoolean(bluetoothDevice.getMetadata(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +201,36 @@ public final class Utils {
|
|||||||
CachedBluetoothDevice cachedDevice) {
|
CachedBluetoothDevice cachedDevice) {
|
||||||
final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription(
|
final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription(
|
||||||
context, cachedDevice);
|
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();
|
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[] iconFgColors = resources.getIntArray(R.array.bt_icon_fg_colors);
|
||||||
final int[] iconBgColors = resources.getIntArray(R.array.bt_icon_bg_colors);
|
final int[] iconBgColors = resources.getIntArray(R.array.bt_icon_bg_colors);
|
||||||
|
|
||||||
|
90
src/com/android/settings/widget/AdaptiveOutlineDrawable.java
Normal file
90
src/com/android/settings/widget/AdaptiveOutlineDrawable.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
@@ -29,6 +29,8 @@ import android.content.Context;
|
|||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
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.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
|
|
||||||
@@ -39,6 +41,7 @@ import org.mockito.Answers;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class UtilsTest {
|
public class UtilsTest {
|
||||||
@@ -51,6 +54,8 @@ public class UtilsTest {
|
|||||||
private Context mContext;
|
private Context mContext;
|
||||||
@Mock
|
@Mock
|
||||||
private BluetoothDevice mBluetoothDevice;
|
private BluetoothDevice mBluetoothDevice;
|
||||||
|
@Mock
|
||||||
|
private CachedBluetoothDevice mCachedBluetoothDevice;
|
||||||
|
|
||||||
private MetricsFeatureProvider mMetricsFeatureProvider;
|
private MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
|
|
||||||
@@ -107,4 +112,16 @@ public class UtilsTest {
|
|||||||
BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).isEqualTo(true);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user