Loading core/java/com/android/internal/util/ContrastColorUtil.java +26 −1 Original line number Diff line number Diff line Loading @@ -586,7 +586,7 @@ public class ContrastColorUtil { * * @param color the base color to use * @param amount the amount from 1 to 100 how much to modify the color * @return the now color that was modified * @return the new color that was modified */ public static int getShiftedColor(int color, int amount) { final double[] result = ColorUtilsFromCompat.getTempDouble3Array(); Loading @@ -599,6 +599,19 @@ public class ContrastColorUtil { return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]); } /** * Blends the provided color with white to create a muted version. * * @param color the color to mute * @param alpha the amount from 0 to 1 to set the alpha component of the white scrim * @return the new color that was modified */ public static int getMutedColor(int color, float alpha) { int whiteScrim = ColorUtilsFromCompat.setAlphaComponent( Color.WHITE, (int) (255 * alpha)); return compositeColors(whiteScrim, color); } private static boolean shouldUseDark(int backgroundColor, boolean defaultBackgroundIsDark) { if (backgroundColor == Notification.COLOR_DEFAULT) { return !defaultBackgroundIsDark; Loading Loading @@ -674,6 +687,18 @@ public class ContrastColorUtil { return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF); } /** * Set the alpha component of {@code color} to be {@code alpha}. */ @ColorInt public static int setAlphaComponent(@ColorInt int color, @IntRange(from = 0x0, to = 0xFF) int alpha) { if (alpha < 0 || alpha > 255) { throw new IllegalArgumentException("alpha must be between 0 and 255."); } return (color & 0x00ffffff) | (alpha << 24); } /** * Returns the luminance of a color as a float between {@code 0.0} and {@code 1.0}. * <p>Defined as the Y component in the XYZ representation of {@code color}.</p> Loading packages/SystemUI/res/layout/bubble_view.xml 0 → 100644 +38 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2018 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 --> <com.android.systemui.bubbles.BubbleView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/bubble_view"> <com.android.systemui.bubbles.BadgedImageView android:id="@+id/bubble_image" android:layout_width="@dimen/bubble_size" android:layout_height="@dimen/bubble_size" android:padding="@dimen/bubble_view_padding" android:clipToPadding="false"/> <TextView android:id="@+id/message_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:minWidth="@dimen/bubble_message_min_width" android:maxWidth="@dimen/bubble_message_max_width" android:padding="@dimen/bubble_message_padding"/> </com.android.systemui.bubbles.BubbleView> packages/SystemUI/res/values/dimens.xml +12 −4 Original line number Diff line number Diff line Loading @@ -981,14 +981,16 @@ <!-- How much a bubble is elevated --> <dimen name="bubble_elevation">8dp</dimen> <!-- Padding around a collapsed bubble --> <dimen name="bubble_view_padding">0dp</dimen> <!-- Padding between bubbles when displayed in expanded state --> <dimen name="bubble_padding">8dp</dimen> <!-- Padding around the view displayed when the bubble is expanded --> <dimen name="bubble_expanded_view_padding">8dp</dimen> <!-- Size of the collapsed bubble --> <dimen name="bubble_size">56dp</dimen> <!-- Size of an icon displayed within the bubble --> <dimen name="bubble_icon_size">24dp</dimen> <!-- How much to inset the icon in the circle --> <dimen name="bubble_icon_inset">16dp</dimen> <!-- Padding around the view displayed when the bubble is expanded --> <dimen name="bubble_expanded_view_padding">8dp</dimen> <!-- Default height of the expanded view shown when the bubble is expanded --> <dimen name="bubble_expanded_default_height">400dp</dimen> <!-- Height of the triangle that points to the expanded bubble --> Loading @@ -1001,4 +1003,10 @@ <dimen name="bubble_expanded_header_height">48dp</dimen> <!-- Left and right padding applied to the header. --> <dimen name="bubble_expanded_header_horizontal_padding">24dp</dimen> <!-- Max width of the message bubble--> <dimen name="bubble_message_max_width">144dp</dimen> <!-- Min width of the message bubble --> <dimen name="bubble_message_min_width">32dp</dimen> <!-- Interior padding of the message bubble --> <dimen name="bubble_message_padding">4dp</dimen> </resources> packages/SystemUI/src/com/android/systemui/bubbles/BadgeRenderer.java 0 → 100644 +80 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.systemui.bubbles; import static android.graphics.Paint.ANTI_ALIAS_FLAG; import static android.graphics.Paint.FILTER_BITMAP_FLAG; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.util.Log; // XXX: Mostly opied from launcher code / can we share? /** * Contains parameters necessary to draw a badge for an icon (e.g. the size of the badge). */ public class BadgeRenderer { private static final String TAG = "BadgeRenderer"; // The badge sizes are defined as percentages of the app icon size. private static final float SIZE_PERCENTAGE = 0.38f; // Extra scale down of the dot private static final float DOT_SCALE = 0.6f; private final float mDotCenterOffset; private final float mCircleRadius; private final Paint mCirclePaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG); public BadgeRenderer(int iconSizePx) { mDotCenterOffset = SIZE_PERCENTAGE * iconSizePx; int size = (int) (DOT_SCALE * mDotCenterOffset); mCircleRadius = size / 2f; } /** * Draw a circle in the top right corner of the given bounds. * * @param color The color (based on the icon) to use for the badge. * @param iconBounds The bounds of the icon being badged. * @param badgeScale The progress of the animation, from 0 to 1. * @param spaceForOffset How much space to offset the badge up and to the left or right. * @param onLeft Whether the badge should be draw on left or right side. */ public void draw(Canvas canvas, int color, Rect iconBounds, float badgeScale, Point spaceForOffset, boolean onLeft) { if (iconBounds == null) { Log.e(TAG, "Invalid null argument(s) passed in call to draw."); return; } canvas.save(); // We draw the badge relative to its center. int x = onLeft ? iconBounds.left : iconBounds.right; float offset = onLeft ? (mDotCenterOffset / 2) : -(mDotCenterOffset / 2); float badgeCenterX = x + offset; float badgeCenterY = iconBounds.top + mDotCenterOffset / 2; canvas.translate(badgeCenterX + spaceForOffset.x, badgeCenterY - spaceForOffset.y); canvas.scale(badgeScale, badgeScale); mCirclePaint.setColor(color); canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint); canvas.restore(); } } packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java 0 → 100644 +129 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.systemui.bubbles; import android.content.Context; import android.graphics.Canvas; import android.graphics.Path; import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; import android.widget.ImageView; import com.android.systemui.R; /** * View that circle crops its contents and supports displaying a coloured dot on a top corner. */ public class BadgedImageView extends ImageView { private BadgeRenderer mDotRenderer; private int mIconSize; private Rect mTempBounds = new Rect(); private Point mTempPoint = new Point(); private Path mClipPath = new Path(); private float mDotScale = 0f; private int mUpdateDotColor; private boolean mShowUpdateDot; private boolean mOnLeft; public BadgedImageView(Context context) { this(context, null); } public BadgedImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); setScaleType(ScaleType.CENTER_CROP); mIconSize = getResources().getDimensionPixelSize(R.dimen.bubble_size); mDotRenderer = new BadgeRenderer(mIconSize); } // TODO: Clipping oval path isn't great: rerender image into a separate, rounded bitmap and // then draw would be better @Override public void onDraw(Canvas canvas) { canvas.save(); // Circle crop mClipPath.addOval(getPaddingStart(), getPaddingTop(), getWidth() - getPaddingEnd(), getHeight() - getPaddingBottom(), Path.Direction.CW); canvas.clipPath(mClipPath); super.onDraw(canvas); // After we've circle cropped what we're showing, restore so we don't clip the badge canvas.restore(); // Draw the badge if (mShowUpdateDot) { getDrawingRect(mTempBounds); mTempPoint.set((getWidth() - mIconSize) / 2, getPaddingTop()); mDotRenderer.draw(canvas, mUpdateDotColor, mTempBounds, mDotScale, mTempPoint, mOnLeft); } } /** * Set whether the dot should appear on left or right side of the view. */ public void setDotPosition(boolean onLeft) { mOnLeft = onLeft; invalidate(); } /** * Set whether the dot should show or not. */ public void setShowDot(boolean showBadge) { mShowUpdateDot = showBadge; invalidate(); } /** * @return whether the dot is being displayed. */ public boolean isShowingDot() { return mShowUpdateDot; } /** * The colour to use for the dot. */ public void setDotColor(int color) { mUpdateDotColor = color; invalidate(); } /** * How big the dot should be, fraction from 0 to 1. */ public void setDotScale(float fraction) { mDotScale = fraction; invalidate(); } public float getDotScale() { return mDotScale; } } Loading
core/java/com/android/internal/util/ContrastColorUtil.java +26 −1 Original line number Diff line number Diff line Loading @@ -586,7 +586,7 @@ public class ContrastColorUtil { * * @param color the base color to use * @param amount the amount from 1 to 100 how much to modify the color * @return the now color that was modified * @return the new color that was modified */ public static int getShiftedColor(int color, int amount) { final double[] result = ColorUtilsFromCompat.getTempDouble3Array(); Loading @@ -599,6 +599,19 @@ public class ContrastColorUtil { return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]); } /** * Blends the provided color with white to create a muted version. * * @param color the color to mute * @param alpha the amount from 0 to 1 to set the alpha component of the white scrim * @return the new color that was modified */ public static int getMutedColor(int color, float alpha) { int whiteScrim = ColorUtilsFromCompat.setAlphaComponent( Color.WHITE, (int) (255 * alpha)); return compositeColors(whiteScrim, color); } private static boolean shouldUseDark(int backgroundColor, boolean defaultBackgroundIsDark) { if (backgroundColor == Notification.COLOR_DEFAULT) { return !defaultBackgroundIsDark; Loading Loading @@ -674,6 +687,18 @@ public class ContrastColorUtil { return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF); } /** * Set the alpha component of {@code color} to be {@code alpha}. */ @ColorInt public static int setAlphaComponent(@ColorInt int color, @IntRange(from = 0x0, to = 0xFF) int alpha) { if (alpha < 0 || alpha > 255) { throw new IllegalArgumentException("alpha must be between 0 and 255."); } return (color & 0x00ffffff) | (alpha << 24); } /** * Returns the luminance of a color as a float between {@code 0.0} and {@code 1.0}. * <p>Defined as the Y component in the XYZ representation of {@code color}.</p> Loading
packages/SystemUI/res/layout/bubble_view.xml 0 → 100644 +38 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2018 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 --> <com.android.systemui.bubbles.BubbleView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/bubble_view"> <com.android.systemui.bubbles.BadgedImageView android:id="@+id/bubble_image" android:layout_width="@dimen/bubble_size" android:layout_height="@dimen/bubble_size" android:padding="@dimen/bubble_view_padding" android:clipToPadding="false"/> <TextView android:id="@+id/message_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:minWidth="@dimen/bubble_message_min_width" android:maxWidth="@dimen/bubble_message_max_width" android:padding="@dimen/bubble_message_padding"/> </com.android.systemui.bubbles.BubbleView>
packages/SystemUI/res/values/dimens.xml +12 −4 Original line number Diff line number Diff line Loading @@ -981,14 +981,16 @@ <!-- How much a bubble is elevated --> <dimen name="bubble_elevation">8dp</dimen> <!-- Padding around a collapsed bubble --> <dimen name="bubble_view_padding">0dp</dimen> <!-- Padding between bubbles when displayed in expanded state --> <dimen name="bubble_padding">8dp</dimen> <!-- Padding around the view displayed when the bubble is expanded --> <dimen name="bubble_expanded_view_padding">8dp</dimen> <!-- Size of the collapsed bubble --> <dimen name="bubble_size">56dp</dimen> <!-- Size of an icon displayed within the bubble --> <dimen name="bubble_icon_size">24dp</dimen> <!-- How much to inset the icon in the circle --> <dimen name="bubble_icon_inset">16dp</dimen> <!-- Padding around the view displayed when the bubble is expanded --> <dimen name="bubble_expanded_view_padding">8dp</dimen> <!-- Default height of the expanded view shown when the bubble is expanded --> <dimen name="bubble_expanded_default_height">400dp</dimen> <!-- Height of the triangle that points to the expanded bubble --> Loading @@ -1001,4 +1003,10 @@ <dimen name="bubble_expanded_header_height">48dp</dimen> <!-- Left and right padding applied to the header. --> <dimen name="bubble_expanded_header_horizontal_padding">24dp</dimen> <!-- Max width of the message bubble--> <dimen name="bubble_message_max_width">144dp</dimen> <!-- Min width of the message bubble --> <dimen name="bubble_message_min_width">32dp</dimen> <!-- Interior padding of the message bubble --> <dimen name="bubble_message_padding">4dp</dimen> </resources>
packages/SystemUI/src/com/android/systemui/bubbles/BadgeRenderer.java 0 → 100644 +80 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.systemui.bubbles; import static android.graphics.Paint.ANTI_ALIAS_FLAG; import static android.graphics.Paint.FILTER_BITMAP_FLAG; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.util.Log; // XXX: Mostly opied from launcher code / can we share? /** * Contains parameters necessary to draw a badge for an icon (e.g. the size of the badge). */ public class BadgeRenderer { private static final String TAG = "BadgeRenderer"; // The badge sizes are defined as percentages of the app icon size. private static final float SIZE_PERCENTAGE = 0.38f; // Extra scale down of the dot private static final float DOT_SCALE = 0.6f; private final float mDotCenterOffset; private final float mCircleRadius; private final Paint mCirclePaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG); public BadgeRenderer(int iconSizePx) { mDotCenterOffset = SIZE_PERCENTAGE * iconSizePx; int size = (int) (DOT_SCALE * mDotCenterOffset); mCircleRadius = size / 2f; } /** * Draw a circle in the top right corner of the given bounds. * * @param color The color (based on the icon) to use for the badge. * @param iconBounds The bounds of the icon being badged. * @param badgeScale The progress of the animation, from 0 to 1. * @param spaceForOffset How much space to offset the badge up and to the left or right. * @param onLeft Whether the badge should be draw on left or right side. */ public void draw(Canvas canvas, int color, Rect iconBounds, float badgeScale, Point spaceForOffset, boolean onLeft) { if (iconBounds == null) { Log.e(TAG, "Invalid null argument(s) passed in call to draw."); return; } canvas.save(); // We draw the badge relative to its center. int x = onLeft ? iconBounds.left : iconBounds.right; float offset = onLeft ? (mDotCenterOffset / 2) : -(mDotCenterOffset / 2); float badgeCenterX = x + offset; float badgeCenterY = iconBounds.top + mDotCenterOffset / 2; canvas.translate(badgeCenterX + spaceForOffset.x, badgeCenterY - spaceForOffset.y); canvas.scale(badgeScale, badgeScale); mCirclePaint.setColor(color); canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint); canvas.restore(); } }
packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java 0 → 100644 +129 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.systemui.bubbles; import android.content.Context; import android.graphics.Canvas; import android.graphics.Path; import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; import android.widget.ImageView; import com.android.systemui.R; /** * View that circle crops its contents and supports displaying a coloured dot on a top corner. */ public class BadgedImageView extends ImageView { private BadgeRenderer mDotRenderer; private int mIconSize; private Rect mTempBounds = new Rect(); private Point mTempPoint = new Point(); private Path mClipPath = new Path(); private float mDotScale = 0f; private int mUpdateDotColor; private boolean mShowUpdateDot; private boolean mOnLeft; public BadgedImageView(Context context) { this(context, null); } public BadgedImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); setScaleType(ScaleType.CENTER_CROP); mIconSize = getResources().getDimensionPixelSize(R.dimen.bubble_size); mDotRenderer = new BadgeRenderer(mIconSize); } // TODO: Clipping oval path isn't great: rerender image into a separate, rounded bitmap and // then draw would be better @Override public void onDraw(Canvas canvas) { canvas.save(); // Circle crop mClipPath.addOval(getPaddingStart(), getPaddingTop(), getWidth() - getPaddingEnd(), getHeight() - getPaddingBottom(), Path.Direction.CW); canvas.clipPath(mClipPath); super.onDraw(canvas); // After we've circle cropped what we're showing, restore so we don't clip the badge canvas.restore(); // Draw the badge if (mShowUpdateDot) { getDrawingRect(mTempBounds); mTempPoint.set((getWidth() - mIconSize) / 2, getPaddingTop()); mDotRenderer.draw(canvas, mUpdateDotColor, mTempBounds, mDotScale, mTempPoint, mOnLeft); } } /** * Set whether the dot should appear on left or right side of the view. */ public void setDotPosition(boolean onLeft) { mOnLeft = onLeft; invalidate(); } /** * Set whether the dot should show or not. */ public void setShowDot(boolean showBadge) { mShowUpdateDot = showBadge; invalidate(); } /** * @return whether the dot is being displayed. */ public boolean isShowingDot() { return mShowUpdateDot; } /** * The colour to use for the dot. */ public void setDotColor(int color) { mUpdateDotColor = color; invalidate(); } /** * How big the dot should be, fraction from 0 to 1. */ public void setDotScale(float fraction) { mDotScale = fraction; invalidate(); } public float getDotScale() { return mDotScale; } }