Refactor BadgedImageView to extend FrameLayout
BadgedImageView was extending ImageView and drew the badge icon on top of the bubble icon. This makes it difficult to animate the app icon among other things.
Refactored BadgedImageView to extend FrameLayout. Moved bubble icon and app icon into separate ImageView's that are added to the FrameLayout.
Bug: 162857077
Test: compared layout before and after the refactor
Test: enabled RTL layout, compared layout before and after the refactor
Change-Id: I18645549a156d7d78eacc223fca39657346e08dd
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
index d92e2cc..686fbbf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
@@ -15,23 +15,22 @@
*/
package com.android.wm.shell.bubbles;
-import static android.graphics.Paint.ANTI_ALIAS_FLAG;
-import static android.graphics.Paint.DITHER_FLAG;
-import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-
+import android.annotation.DrawableRes;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Outline;
-import android.graphics.Paint;
-import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.PathParser;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewOutlineProvider;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.launcher3.icons.DotRenderer;
@@ -47,7 +46,7 @@
* Badge = the icon associated with the app that created this bubble, this will show work profile
* badge if appropriate.
*/
-public class BadgedImageView extends ImageView {
+public class BadgedImageView extends FrameLayout {
/** Same value as Launcher3 dot code */
public static final float WHITE_SCRIM_ALPHA = 0.54f;
@@ -74,6 +73,9 @@
private final EnumSet<SuppressionFlag> mDotSuppressionFlags =
EnumSet.of(SuppressionFlag.FLYOUT_VISIBLE);
+ private final ImageView mBubbleIcon;
+ private final ImageView mAppIcon;
+
private float mDotScale = 0f;
private float mAnimatingToDotScale = 0f;
private boolean mDotIsAnimating = false;
@@ -86,7 +88,6 @@
private DotRenderer.DrawParams mDrawParams;
private int mDotColor;
- private Paint mPaint = new Paint(ANTI_ALIAS_FLAG);
private Rect mTempBounds = new Rect();
public BadgedImageView(Context context) {
@@ -104,6 +105,17 @@
public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+
+ mBubbleIcon = new ImageView(context);
+ addView(mBubbleIcon);
+ mAppIcon = new ImageView(context);
+ addView(mAppIcon);
+
+ final TypedArray ta = mContext.obtainStyledAttributes(attrs, new int[]{android.R.attr.src},
+ defStyleAttr, defStyleRes);
+ mBubbleIcon.setImageResource(ta.getResourceId(0, 0));
+ ta.recycle();
+
mDrawParams = new DotRenderer.DrawParams();
setFocusable(true);
@@ -135,7 +147,6 @@
public void showDotAndBadge(boolean onLeft) {
removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.BEHIND_STACK);
animateDotBadgePositions(onLeft);
-
}
public void hideDotAndBadge(boolean onLeft) {
@@ -149,6 +160,7 @@
*/
public void setRenderedBubble(BubbleViewProvider bubble) {
mBubble = bubble;
+ mBubbleIcon.setImageBitmap(bubble.getBubbleIcon());
if (mDotSuppressionFlags.contains(SuppressionFlag.BEHIND_STACK)) {
hideBadge();
} else {
@@ -176,6 +188,20 @@
mDotRenderer.draw(canvas, mDrawParams);
}
+ /**
+ * Set drawable resource shown as the icon
+ */
+ public void setIconImageResource(@DrawableRes int drawable) {
+ mBubbleIcon.setImageResource(drawable);
+ }
+
+ /**
+ * Get icon drawable
+ */
+ public Drawable getIconDrawable() {
+ return mBubbleIcon.getDrawable();
+ }
+
/** Adds a dot suppression flag, updating dot visibility if needed. */
void addDotSuppressionFlag(SuppressionFlag flag) {
if (mDotSuppressionFlags.add(flag)) {
@@ -279,7 +305,6 @@
showBadge();
}
-
/** Whether to draw the dot in onDraw(). */
private boolean shouldDrawDot() {
// Always render the dot if it's animating, since it could be animating out. Otherwise, show
@@ -325,29 +350,28 @@
void showBadge() {
Bitmap badge = mBubble.getAppBadge();
if (badge == null) {
- setImageBitmap(mBubble.getBubbleIcon());
+ mAppIcon.setVisibility(GONE);
return;
}
- Canvas bubbleCanvas = new Canvas();
- Bitmap noBadgeBubble = mBubble.getBubbleIcon();
- Bitmap bubble = noBadgeBubble.copy(noBadgeBubble.getConfig(), /* isMutable */ true);
- bubbleCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG));
- bubbleCanvas.setBitmap(bubble);
- final int bubbleSize = bubble.getWidth();
+ final int bubbleSize = mBubble.getBubbleIcon().getWidth();
final int badgeSize = (int) (ICON_BADGE_SCALE * bubbleSize);
- Rect dest = new Rect();
+
+ FrameLayout.LayoutParams appIconParams = (LayoutParams) mAppIcon.getLayoutParams();
+ appIconParams.height = badgeSize;
+ appIconParams.width = badgeSize;
if (mOnLeft) {
- dest.set(0, bubbleSize - badgeSize, badgeSize, bubbleSize);
+ appIconParams.gravity = Gravity.BOTTOM | Gravity.LEFT;
} else {
- dest.set(bubbleSize - badgeSize, bubbleSize - badgeSize, bubbleSize, bubbleSize);
+ appIconParams.gravity = Gravity.BOTTOM | Gravity.RIGHT;
}
- bubbleCanvas.drawBitmap(badge, null /* src */, dest, mPaint);
- bubbleCanvas.setBitmap(null);
- setImageBitmap(bubble);
+ mAppIcon.setLayoutParams(appIconParams);
+
+ mAppIcon.setImageBitmap(badge);
+ mAppIcon.setVisibility(VISIBLE);
}
void hideBadge() {
- setImageBitmap(mBubble.getBubbleIcon());
+ mAppIcon.setVisibility(GONE);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index 5161092..a175929 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -66,7 +66,7 @@
updateResources()
getExpandedView()?.applyThemeAttrs()
// Apply inset and new style to fresh icon drawable.
- getIconView()?.setImageResource(R.drawable.bubble_ic_overflow_button)
+ getIconView()?.setIconImageResource(R.drawable.bubble_ic_overflow_button)
updateBtnTheme()
}
@@ -89,19 +89,19 @@
dotColor = colorAccent
val shapeColor = res.getColor(android.R.color.system_accent1_1000)
- overflowBtn?.drawable?.setTint(shapeColor)
+ overflowBtn?.iconDrawable?.setTint(shapeColor)
val iconFactory = BubbleIconFactory(context)
// Update bitmap
- val fg = InsetDrawable(overflowBtn?.drawable, overflowIconInset)
+ val fg = InsetDrawable(overflowBtn?.iconDrawable, overflowIconInset)
bitmap = iconFactory.createBadgedIconBitmap(
AdaptiveIconDrawable(ColorDrawable(colorAccent), fg)).icon
// Update dot path
dotPath = PathParser.createPathFromPathData(
res.getString(com.android.internal.R.string.config_icon_mask))
- val scale = iconFactory.normalizer.getScale(iconView!!.drawable,
+ val scale = iconFactory.normalizer.getScale(iconView!!.iconDrawable,
null /* outBounds */, null /* path */, null /* outMaskShape */)
val radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f
val matrix = Matrix()