Merge "Enable left badge, hidden badge"
This commit is contained in:
committed by
Android (Google) Code Review
commit
28733d0275
@@ -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());
|
||||
}
|
||||
@@ -160,14 +170,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.
|
||||
*/
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 nightMode = (res.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
||||
== Configuration.UI_MODE_NIGHT_YES)
|
||||
val bg = ColorDrawable(res.getColor(
|
||||
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 */)
|
||||
bitmap = iconFactory.createBadgedIconBitmap(AdaptiveIconDrawable(bg, fg),
|
||||
null /* user */, true /* shrinkNonAdaptiveIcons */).icon
|
||||
|
||||
// Set dot path
|
||||
// Update bitmap
|
||||
val nightMode = (res.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
||||
== Configuration.UI_MODE_NIGHT_YES)
|
||||
val bg = ColorDrawable(res.getColor(
|
||||
if (nightMode) R.color.bubbles_dark else R.color.bubbles_light))
|
||||
|
||||
val fg = InsetDrawable(overflowBtn.drawable,
|
||||
bitmapSize - iconBitmapSize /* inset */)
|
||||
bitmap = iconFactory.createBadgedIconBitmap(AdaptiveIconDrawable(bg, fg),
|
||||
null /* user */, true /* shrinkNonAdaptiveIcons */).icon
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
BadgedImageView.SuppressionFlag.BEHIND_STACK);
|
||||
} else {
|
||||
if (mIsExpanded) {
|
||||
bv.removeDotSuppressionFlag(
|
||||
BadgedImageView.SuppressionFlag.BEHIND_STACK);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
|
||||
/** App badge drawable to draw above bubble icon. */
|
||||
@Nullable Drawable getAppBadge();
|
||||
|
||||
/** Path of normalized bubble icon to draw dot on. */
|
||||
Path getDotPath();
|
||||
|
||||
int getDotColor();
|
||||
|
||||
Path getDotPath();
|
||||
|
||||
boolean showDot();
|
||||
|
||||
int getDisplayId();
|
||||
|
||||
Reference in New Issue
Block a user