diff options
7 files changed, 131 insertions, 92 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java index a86a46960bcb..9f7358bf94ff 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java @@ -17,9 +17,12 @@ package com.android.systemui.bubbles; import android.annotation.Nullable; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.Canvas; +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.widget.ImageView; @@ -30,6 +33,9 @@ import com.android.systemui.R; import java.util.EnumSet; +import static android.graphics.Paint.DITHER_FLAG; +import static android.graphics.Paint.FILTER_BITMAP_FLAG; + /** * View that displays an adaptive icon with an app-badge and a dot. * @@ -43,6 +49,8 @@ public class BadgedImageView extends ImageView { public static final float WHITE_SCRIM_ALPHA = 0.54f; /** Same as value in Launcher3 IconShape */ public static final int DEFAULT_PATH_SIZE = 100; + /** Same as value in Launcher3 BaseIconFactory */ + private static final float ICON_BADGE_SCALE = 0.444f; /** * Flags that suppress the visibility of the 'new' dot, for one reason or another. If any of @@ -69,6 +77,7 @@ public class BadgedImageView extends ImageView { private BubbleViewProvider mBubble; private int mBubbleBitmapSize; + private int mBubbleSize; private DotRenderer mDotRenderer; private DotRenderer.DrawParams mDrawParams; private boolean mOnLeft; @@ -93,6 +102,7 @@ public class BadgedImageView extends ImageView { int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mBubbleBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size); + mBubbleSize = getResources().getDimensionPixelSize(R.dimen.individual_bubble_size); mDrawParams = new DotRenderer.DrawParams(); Path iconPath = PathParser.createPathFromPathData( @@ -108,7 +118,7 @@ public class BadgedImageView extends ImageView { */ public void setRenderedBubble(BubbleViewProvider bubble) { mBubble = bubble; - setImageBitmap(bubble.getBadgedImage()); + showBadge(); mDotColor = bubble.getDotColor(); drawDot(bubble.getDotPath()); } @@ -161,14 +171,6 @@ public class BadgedImageView extends ImageView { } /** - * Set whether the dot should appear on left or right side of the view. - */ - void setDotOnLeft(boolean onLeft) { - mOnLeft = onLeft; - invalidate(); - } - - /** * @param iconPath The new icon path to use when calculating dot position. */ void drawDot(Path iconPath) { @@ -219,22 +221,29 @@ public class BadgedImageView extends ImageView { return mDotColor; } - /** Sets the position of the 'new' dot, animating it out and back in if requested. */ - void setDotPositionOnLeft(boolean onLeft, boolean animate) { - if (animate && onLeft != getDotOnLeft() && shouldDrawDot()) { + /** Sets the position of the dot and badge, animating them out and back in if requested. */ + void animateDotBadgePositions(boolean onLeft) { + mOnLeft = onLeft; + + if (onLeft != getDotOnLeft() && shouldDrawDot()) { animateDotScale(0f /* showDot */, () -> { - setDotOnLeft(onLeft); + invalidate(); animateDotScale(1.0f, null /* after */); }); - } else { - setDotOnLeft(onLeft); } + // TODO animate badge + showBadge(); + } - boolean getDotPositionOnLeft() { - return getDotOnLeft(); + /** Sets the position of the dot and badge. */ + void setDotBadgeOnLeft(boolean onLeft) { + mOnLeft = onLeft; + invalidate(); + 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 @@ -276,4 +285,33 @@ public class BadgedImageView extends ImageView { } }).start(); } + + void showBadge() { + Drawable badge = mBubble.getAppBadge(); + if (badge == null) { + setImageBitmap(mBubble.getBubbleIcon()); + 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 badgeSize = (int) (ICON_BADGE_SCALE * mBubbleSize); + if (mOnLeft) { + badge.setBounds(0, mBubbleSize - badgeSize, badgeSize, mBubbleSize); + } else { + badge.setBounds(mBubbleSize - badgeSize, mBubbleSize - badgeSize, + mBubbleSize, mBubbleSize); + } + badge.draw(bubbleCanvas); + bubbleCanvas.setBitmap(null); + setImageBitmap(bubble); + } + + void hideBadge() { + setImageBitmap(mBubble.getBubbleIcon()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java index 62bc425b2bd2..e6c1bc3d4c6c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java @@ -41,7 +41,6 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.InstanceId; -import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.io.FileDescriptor; @@ -92,8 +91,9 @@ class Bubble implements BubbleViewProvider { } private FlyoutMessage mFlyoutMessage; - private Drawable mBadgedAppIcon; - private Bitmap mBadgedImage; + private Drawable mBadgeDrawable; + // Bitmap with no badge, no dot + private Bitmap mBubbleBitmap; private int mDotColor; private Path mDotPath; private int mFlags; @@ -199,12 +199,13 @@ class Bubble implements BubbleViewProvider { } @Override - public Bitmap getBadgedImage() { - return mBadgedImage; + public Bitmap getBubbleIcon() { + return mBubbleBitmap; } - public Drawable getBadgedAppIcon() { - return mBadgedAppIcon; + @Override + public Drawable getAppBadge() { + return mBadgeDrawable; } @Override @@ -340,8 +341,9 @@ class Bubble implements BubbleViewProvider { mAppName = info.appName; mFlyoutMessage = info.flyoutMessage; - mBadgedAppIcon = info.badgedAppIcon; - mBadgedImage = info.badgedBubbleImage; + mBadgeDrawable = info.badgeDrawable; + mBubbleBitmap = info.bubbleBitmap; + mDotColor = info.dotColor; mDotPath = info.dotPath; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java index d017bc0e31c2..371e8490d235 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java @@ -156,17 +156,4 @@ public class BubbleIconFactory extends BaseIconFactory { canvas.setBitmap(null); return bitmap; } - - /** - * Returns a {@link BitmapInfo} for the entire bubble icon including the badge. - */ - BitmapInfo getBubbleBitmap(Drawable bubble, BitmapInfo badge) { - BitmapInfo bubbleIconInfo = createBadgedIconBitmap(bubble, - null /* user */, - true /* shrinkNonAdaptiveIcons */); - - badgeWithDrawable(bubbleIconInfo.icon, - new BitmapDrawable(mContext.getResources(), badge.icon)); - return bubbleIconInfo; - } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt index 155b71b99ff9..6d3c2a68e6c7 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt @@ -23,6 +23,7 @@ import android.graphics.Matrix import android.graphics.Path import android.graphics.drawable.AdaptiveIconDrawable import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable import android.graphics.drawable.InsetDrawable import android.util.PathParser import android.util.TypedValue @@ -36,8 +37,9 @@ class BubbleOverflow( private val stack: BubbleStackView ) : BubbleViewProvider { - private var bitmap: Bitmap? = null - private var dotPath: Path? = null + private lateinit var bitmap : Bitmap + private lateinit var dotPath : Path + private var bitmapSize = 0 private var iconBitmapSize = 0 private var dotColor = 0 @@ -80,40 +82,41 @@ class BubbleOverflow( expandedView.updateDimensions() } - fun updateBtnTheme() { + private fun updateBtnTheme() { val res = context.resources // Set overflow button accent color, dot color val typedValue = TypedValue() context.theme.resolveAttribute(android.R.attr.colorAccent, typedValue, true) - val colorAccent = res.getColor(typedValue.resourceId) - overflowBtn.getDrawable()?.setTint(colorAccent) + overflowBtn.drawable?.setTint(colorAccent) dotColor = colorAccent - // Set button and activity background color + val iconFactory = BubbleIconFactory(context) + + // Update bitmap val nightMode = (res.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK - == Configuration.UI_MODE_NIGHT_YES) + == Configuration.UI_MODE_NIGHT_YES) val bg = ColorDrawable(res.getColor( - if (nightMode) R.color.bubbles_dark else R.color.bubbles_light)) + if (nightMode) R.color.bubbles_dark else R.color.bubbles_light)) - // Set button icon - val iconFactory = BubbleIconFactory(context) - val fg = InsetDrawable(overflowBtn.getDrawable(), - bitmapSize - iconBitmapSize /* inset */) + val fg = InsetDrawable(overflowBtn.drawable, + bitmapSize - iconBitmapSize /* inset */) bitmap = iconFactory.createBadgedIconBitmap(AdaptiveIconDrawable(bg, fg), - null /* user */, true /* shrinkNonAdaptiveIcons */).icon + null /* user */, true /* shrinkNonAdaptiveIcons */).icon - // Set dot path + // Update dot path dotPath = PathParser.createPathFromPathData( - res.getString(com.android.internal.R.string.config_icon_mask)) + res.getString(com.android.internal.R.string.config_icon_mask)) val scale = iconFactory.normalizer.getScale(overflowBtn.getDrawable(), - null /* outBounds */, null /* path */, null /* outMaskShape */) + null /* outBounds */, null /* path */, null /* outMaskShape */) val radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f val matrix = Matrix() matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */, - radius /* pivot y */) - dotPath?.transform(matrix) + radius /* pivot y */) + dotPath.transform(matrix) + + // Attach BubbleOverflow to BadgedImageView overflowBtn.setRenderedBubble(this) } @@ -129,7 +132,11 @@ class BubbleOverflow( return dotColor } - override fun getBadgedImage(): Bitmap? { + override fun getAppBadge(): Drawable? { + return null + } + + override fun getBubbleIcon(): Bitmap { return bitmap } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index c1b68824d20f..55f96312d8a2 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -16,13 +16,6 @@ package com.android.systemui.bubbles; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; - -import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW; -import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES; -import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -99,6 +92,12 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW; +import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES; +import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; + /** * Renders bubbles in a stack and handles animating expanded and collapsed states. */ @@ -658,13 +657,10 @@ public class BubbleStackView extends FrameLayout mStackOnLeftOrWillBe = mStackAnimationController.flingStackThenSpringToEdge( viewInitialX + dx, velX, velY) <= 0; - - updateBubbleZOrdersAndDotPosition(true /* animate */); - + updateBubbleIcons(); logBubbleEvent(null /* no bubble associated with bubble stack move */, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED); } - mDismissView.hide(); } @@ -1468,8 +1464,7 @@ public class BubbleStackView extends FrameLayout // Set the dot position to the opposite of the side the stack is resting on, since the stack // resting slightly off-screen would result in the dot also being off-screen. - bubble.getIconView().setDotPositionOnLeft( - !mStackOnLeftOrWillBe /* onLeft */, false /* animate */); + bubble.getIconView().setDotBadgeOnLeft(!mStackOnLeftOrWillBe /* onLeft */); bubble.getIconView().setOnClickListener(mBubbleClickListener); bubble.getIconView().setOnTouchListener(mBubbleTouchListener); @@ -1520,7 +1515,7 @@ public class BubbleStackView extends FrameLayout Bubble bubble = bubbles.get(i); mBubbleContainer.reorderView(bubble.getIconView(), i); } - updateBubbleZOrdersAndDotPosition(false /* animate */); + updateBubbleIcons(); updatePointerPosition(); } @@ -2363,7 +2358,7 @@ public class BubbleStackView extends FrameLayout // name and icon. if (show && mBubbleData.hasBubbleInStackWithKey(mExpandedBubble.getKey())) { final Bubble bubble = mBubbleData.getBubbleInStackWithKey(mExpandedBubble.getKey()); - mManageSettingsIcon.setImageDrawable(bubble.getBadgedAppIcon()); + mManageSettingsIcon.setImageDrawable(bubble.getAppBadge()); mManageSettingsText.setText(getResources().getString( R.string.bubbles_app_settings, bubble.getAppName())); } @@ -2551,28 +2546,31 @@ public class BubbleStackView extends FrameLayout } mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide(); - updateBubbleZOrdersAndDotPosition(false); + updateBubbleIcons(); } - /** Sets the appropriate Z-order and dot position for each bubble in the stack. */ - private void updateBubbleZOrdersAndDotPosition(boolean animate) { + /** + * Sets the appropriate Z-order, badge, and dot position for each bubble in the stack. + * Animate dot and badge changes. + */ + private void updateBubbleIcons() { int bubbleCount = getBubbleCount(); for (int i = 0; i < bubbleCount; i++) { BadgedImageView bv = (BadgedImageView) mBubbleContainer.getChildAt(i); bv.setZ((mMaxBubbles * mBubbleElevation) - i); - // If the dot is on the left, and so is the stack, we need to change the dot position. - if (bv.getDotPositionOnLeft() == mStackOnLeftOrWillBe) { - bv.setDotPositionOnLeft(!mStackOnLeftOrWillBe, animate); - } - - if (!mIsExpanded && i > 0) { - // If we're collapsed and this bubble is behind other bubbles, suppress its dot. - bv.addDotSuppressionFlag( + if (mIsExpanded) { + bv.removeDotSuppressionFlag( BadgedImageView.SuppressionFlag.BEHIND_STACK); - } else { + bv.animateDotBadgePositions(false /* onLeft */); + } else if (i == 0) { bv.removeDotSuppressionFlag( BadgedImageView.SuppressionFlag.BEHIND_STACK); + bv.animateDotBadgePositions(!mStackOnLeftOrWillBe); + } else { + bv.addDotSuppressionFlag( + BadgedImageView.SuppressionFlag.BEHIND_STACK); + bv.hideBadge(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java index 5749169b881a..28757facc220 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java @@ -120,8 +120,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask BubbleExpandedView expandedView; ShortcutInfo shortcutInfo; String appName; - Bitmap badgedBubbleImage; - Drawable badgedAppIcon; + Bitmap bubbleBitmap; + Drawable badgeDrawable; int dotColor; Path dotPath; Bubble.FlyoutMessage flyoutMessage; @@ -179,9 +179,10 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon, b.isImportantConversation()); - info.badgedAppIcon = badgedIcon; - info.badgedBubbleImage = iconFactory.getBubbleBitmap(bubbleDrawable, - badgeBitmapInfo).icon; + info.badgeDrawable = badgedIcon; + info.bubbleBitmap = iconFactory.createBadgedIconBitmap(bubbleDrawable, + null /* user */, + true /* shrinkNonAdaptiveIcons */).icon; // Dot color & placement Path iconPath = PathParser.createPathFromPathData( diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java index f1a01be48397..916ad18b2812 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java @@ -18,6 +18,7 @@ package com.android.systemui.bubbles; import android.graphics.Bitmap; import android.graphics.Path; +import android.graphics.drawable.Drawable; import android.view.View; import androidx.annotation.Nullable; @@ -34,12 +35,17 @@ interface BubbleViewProvider { String getKey(); - Bitmap getBadgedImage(); + /** Bubble icon bitmap with no badge and no dot. */ + Bitmap getBubbleIcon(); - int getDotColor(); + /** App badge drawable to draw above bubble icon. */ + @Nullable Drawable getAppBadge(); + /** Path of normalized bubble icon to draw dot on. */ Path getDotPath(); + int getDotColor(); + boolean showDot(); int getDisplayId(); |