Merge "Update icon badges to match spec" into ub-launcher3-dorval

This commit is contained in:
TreeHugger Robot
2017-04-25 20:02:37 +00:00
committed by Android (Google) Code Review
10 changed files with 177 additions and 102 deletions
-2
View File
@@ -182,8 +182,6 @@
<dimen name="system_shortcut_header_icon_padding">12dp</dimen> <dimen name="system_shortcut_header_icon_padding">12dp</dimen>
<!-- Icon badges (with notification counts) --> <!-- Icon badges (with notification counts) -->
<dimen name="badge_size">24dp</dimen>
<dimen name="badge_text_size">12dp</dimen>
<dimen name="badge_small_padding">0dp</dimen> <dimen name="badge_small_padding">0dp</dimen>
<dimen name="badge_large_padding">3dp</dimen> <dimen name="badge_large_padding">3dp</dimen>
+89 -1
View File
@@ -16,6 +16,7 @@
package com.android.launcher3; package com.android.launcher3;
import android.animation.ObjectAnimator;
import android.content.Context; import android.content.Context;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.Resources; import android.content.res.Resources;
@@ -23,9 +24,12 @@ import android.content.res.TypedArray;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region; import android.graphics.Region;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Property;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -42,6 +46,7 @@ import com.android.launcher3.badge.BadgeRenderer;
import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.DrawableFactory; import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.HolographicOutlineHelper; import com.android.launcher3.graphics.HolographicOutlineHelper;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.graphics.PreloadIconDrawable; import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupContainerWithArrow;
@@ -90,6 +95,28 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
@ViewDebug.ExportedProperty(category = "launcher") @ViewDebug.ExportedProperty(category = "launcher")
private int mTextColor; private int mTextColor;
private BadgeInfo mBadgeInfo;
private BadgeRenderer mBadgeRenderer;
private IconPalette mIconPalette;
private float mBadgeScale;
private boolean mForceHideBadge;
private Point mTempSpaceForBadgeOffset = new Point();
private Rect mTempIconBounds = new Rect();
private static final Property<BubbleTextView, Float> BADGE_SCALE_PROPERTY
= new Property<BubbleTextView, Float>(Float.TYPE, "badgeScale") {
@Override
public Float get(BubbleTextView bubbleTextView) {
return bubbleTextView.mBadgeScale;
}
@Override
public void set(BubbleTextView bubbleTextView, Float value) {
bubbleTextView.mBadgeScale = value;
bubbleTextView.invalidate();
}
};
@ViewDebug.ExportedProperty(category = "launcher") @ViewDebug.ExportedProperty(category = "launcher")
private boolean mStayPressed; private boolean mStayPressed;
@ViewDebug.ExportedProperty(category = "launcher") @ViewDebug.ExportedProperty(category = "launcher")
@@ -369,6 +396,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
if (!mCustomShadowsEnabled) { if (!mCustomShadowsEnabled) {
super.draw(canvas); super.draw(canvas);
drawBadgeIfNecessary(canvas);
return; return;
} }
@@ -395,6 +423,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
if ((getCurrentTextColor() >> 24) == 0) { if ((getCurrentTextColor() >> 24) == 0) {
getPaint().clearShadowLayer(); getPaint().clearShadowLayer();
super.draw(canvas); super.draw(canvas);
drawBadgeIfNecessary(canvas);
return; return;
} }
@@ -410,6 +439,50 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
density * KEY_SHADOW_RADIUS, 0.0f, density * KEY_SHADOW_OFFSET, KEY_SHADOW_COLOR); density * KEY_SHADOW_RADIUS, 0.0f, density * KEY_SHADOW_OFFSET, KEY_SHADOW_COLOR);
super.draw(canvas); super.draw(canvas);
canvas.restore(); canvas.restore();
drawBadgeIfNecessary(canvas);
}
/**
* Draws the icon badge in the top right corner of the icon bounds.
* @param canvas The canvas to draw to.
*/
private void drawBadgeIfNecessary(Canvas canvas) {
if (!mForceHideBadge && (hasBadge() || mBadgeScale > 0)) {
getIconBounds(mTempIconBounds);
mTempSpaceForBadgeOffset.set((getWidth() - mIconSize) / 2, getPaddingTop());
final int scrollX = getScrollX();
final int scrollY = getScrollY();
canvas.translate(scrollX, scrollY);
mBadgeRenderer.draw(canvas, mIconPalette, mBadgeInfo, mTempIconBounds, mBadgeScale,
mTempSpaceForBadgeOffset);
canvas.translate(-scrollX, -scrollY);
}
}
public void forceHideBadge(boolean forceHideBadge) {
if (mForceHideBadge == forceHideBadge) {
return;
}
mForceHideBadge = forceHideBadge;
if (forceHideBadge) {
invalidate();
} else if (hasBadge()) {
ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, 0, 1).start();
}
}
private boolean hasBadge() {
return (mBadgeInfo != null && mBadgeInfo.getNotificationCount() > 0);
}
public void getIconBounds(Rect outBounds) {
int top = getPaddingTop();
int left = (getWidth() - mIconSize) / 2;
int right = left + mIconSize;
int bottom = top + mIconSize;
outBounds.set(left, top, right, bottom);
} }
@Override @Override
@@ -506,7 +579,22 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
if (popup != null) { if (popup != null) {
popup.updateNotificationHeader(badgeInfo, itemInfo); popup.updateNotificationHeader(badgeInfo, itemInfo);
} }
((FastBitmapDrawable) mIcon).applyIconBadge(badgeInfo, badgeRenderer, animate);
boolean wasBadged = mBadgeInfo != null;
boolean isBadged = badgeInfo != null;
float newBadgeScale = isBadged ? 1f : 0;
mBadgeInfo = badgeInfo;
mBadgeRenderer = badgeRenderer;
if (wasBadged || isBadged) {
mIconPalette = ((FastBitmapDrawable) mIcon).getIconPalette();
// Animate when a badge is first added or when it is removed.
if (animate && (wasBadged ^ isBadged) && isShown()) {
ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, newBadgeScale).start();
} else {
mBadgeScale = newBadgeScale;
invalidate();
}
}
} }
} }
+3 -2
View File
@@ -197,8 +197,6 @@ public class DeviceProfile {
hotseatBarBottomPaddingPx = 0; hotseatBarBottomPaddingPx = 0;
hotseatLandGutterPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_gutter_width); hotseatLandGutterPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_gutter_width);
mBadgeRenderer = new BadgeRenderer(context);
// Determine sizes. // Determine sizes.
widthPx = width; widthPx = width;
heightPx = height; heightPx = height;
@@ -213,6 +211,9 @@ public class DeviceProfile {
// Calculate the remaining vars // Calculate the remaining vars
updateAvailableDimensions(dm, res); updateAvailableDimensions(dm, res);
computeAllAppsButtonSize(context); computeAllAppsButtonSize(context);
// This is done last, after iconSizePx is calculated above.
mBadgeRenderer = new BadgeRenderer(context, iconSizePx);
} }
DeviceProfile getMultiWindowProfile(Context context, Point mwSize) { DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
@@ -32,8 +32,6 @@ import android.graphics.drawable.Drawable;
import android.util.Property; import android.util.Property;
import android.util.SparseArray; import android.util.SparseArray;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.badge.BadgeRenderer;
import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.graphics.IconPalette;
public class FastBitmapDrawable extends Drawable { public class FastBitmapDrawable extends Drawable {
@@ -77,24 +75,7 @@ public class FastBitmapDrawable extends Drawable {
private boolean mIsPressed; private boolean mIsPressed;
private boolean mIsDisabled; private boolean mIsDisabled;
private BadgeInfo mBadgeInfo;
private BadgeRenderer mBadgeRenderer;
private IconPalette mIconPalette; private IconPalette mIconPalette;
private float mBadgeScale;
private static final Property<FastBitmapDrawable, Float> BADGE_SCALE_PROPERTY
= new Property<FastBitmapDrawable, Float>(Float.TYPE, "badgeScale") {
@Override
public Float get(FastBitmapDrawable fastBitmapDrawable) {
return fastBitmapDrawable.mBadgeScale;
}
@Override
public void set(FastBitmapDrawable fastBitmapDrawable, Float value) {
fastBitmapDrawable.mBadgeScale = value;
fastBitmapDrawable.invalidateSelf();
}
};
private static final Property<FastBitmapDrawable, Float> BRIGHTNESS private static final Property<FastBitmapDrawable, Float> BRIGHTNESS
= new Property<FastBitmapDrawable, Float>(Float.TYPE, "brightness") { = new Property<FastBitmapDrawable, Float>(Float.TYPE, "brightness") {
@@ -124,30 +105,9 @@ public class FastBitmapDrawable extends Drawable {
setFilterBitmap(true); setFilterBitmap(true);
} }
public void applyIconBadge(final BadgeInfo badgeInfo, BadgeRenderer badgeRenderer,
boolean animate) {
boolean wasBadged = mBadgeInfo != null;
boolean isBadged = badgeInfo != null;
float newBadgeScale = isBadged ? 1f : 0;
mBadgeInfo = badgeInfo;
mBadgeRenderer = badgeRenderer;
if (wasBadged || isBadged) {
mIconPalette = getIconPalette();
// Animate when a badge is first added or when it is removed.
if (animate && (wasBadged ^ isBadged) && isVisible()) {
ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, newBadgeScale).start();
} else {
mBadgeScale = newBadgeScale;
invalidateSelf();
}
}
}
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
drawInternal(canvas); drawInternal(canvas);
// Draw the icon badge in the top right corner.
drawBadgeIfNecessary(canvas);
} }
public void drawWithBrightness(Canvas canvas, float brightness) { public void drawWithBrightness(Canvas canvas, float brightness) {
@@ -161,12 +121,6 @@ public class FastBitmapDrawable extends Drawable {
canvas.drawBitmap(mBitmap, null, getBounds(), mPaint); canvas.drawBitmap(mBitmap, null, getBounds(), mPaint);
} }
protected void drawBadgeIfNecessary(Canvas canvas) {
if (hasBadge()) {
mBadgeRenderer.draw(canvas, mIconPalette, mBadgeInfo, getBounds(), mBadgeScale);
}
}
public IconPalette getIconPalette() { public IconPalette getIconPalette() {
if (mIconPalette == null) { if (mIconPalette == null) {
mIconPalette = IconPalette.fromDominantColor(Utilities mIconPalette = IconPalette.fromDominantColor(Utilities
@@ -175,10 +129,6 @@ public class FastBitmapDrawable extends Drawable {
return mIconPalette; return mIconPalette;
} }
private boolean hasBadge() {
return (mBadgeInfo != null && mBadgeInfo.getNotificationCount() > 0) || mBadgeScale > 0;
}
@Override @Override
public void setColorFilter(ColorFilter cf) { public void setColorFilter(ColorFilter cf) {
// No op // No op
+4 -8
View File
@@ -2247,16 +2247,12 @@ public class Workspace extends PagedView
Point dragVisualizeOffset = null; Point dragVisualizeOffset = null;
Rect dragRect = null; Rect dragRect = null;
if (child instanceof BubbleTextView) { if (child instanceof BubbleTextView) {
int iconSize = grid.iconSizePx; dragRect = new Rect();
int top = child.getPaddingTop(); ((BubbleTextView) child).getIconBounds(dragRect);
int left = (b.getWidth() - iconSize) / 2; dragLayerY += dragRect.top;
int right = left + iconSize; // Note: The dragRect is used to calculate drag layer offsets, but the
int bottom = top + iconSize;
dragLayerY += top;
// Note: The drag region is used to calculate drag layer offsets, but the
// dragVisualizeOffset in addition to the dragRect (the size) to position the outline. // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
dragVisualizeOffset = new Point(- halfPadding, halfPadding); dragVisualizeOffset = new Point(- halfPadding, halfPadding);
dragRect = new Rect(left, top, right, bottom);
} else if (child instanceof FolderIcon) { } else if (child instanceof FolderIcon) {
int previewSize = grid.folderIconSizePx; int previewSize = grid.folderIconSizePx;
dragVisualizeOffset = new Point(- halfPadding, halfPadding - child.getPaddingTop()); dragVisualizeOffset = new Point(- halfPadding, halfPadding - child.getPaddingTop());
@@ -22,9 +22,11 @@ import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Shader; import android.graphics.Shader;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.SparseArray;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.graphics.IconPalette;
@@ -36,31 +38,41 @@ import com.android.launcher3.graphics.ShadowGenerator;
*/ */
public class BadgeRenderer { public class BadgeRenderer {
// The badge sizes are defined as percentages of the app icon size.
private static final float SIZE_PERCENTAGE = 0.38f;
// Used to expand the width of the badge for each additional digit.
private static final float CHAR_SIZE_PERCENTAGE = 0.12f;
private static final float TEXT_SIZE_PERCENTAGE = 0.26f;
private static final float OFFSET_PERCENTAGE = 0.02f;
private final Context mContext; private final Context mContext;
private final int mSize; private final int mSize;
private final int mCharSize;
private final int mTextHeight; private final int mTextHeight;
private final int mOffset;
private final IconDrawer mLargeIconDrawer; private final IconDrawer mLargeIconDrawer;
private final IconDrawer mSmallIconDrawer; private final IconDrawer mSmallIconDrawer;
private final Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG); | Paint.FILTER_BITMAP_FLAG);
private final Bitmap mBackgroundWithShadow; private final SparseArray<Bitmap> mBackgroundsWithShadow;
public BadgeRenderer(final Context context) { public BadgeRenderer(Context context, int iconSizePx) {
mContext = context; mContext = context;
Resources res = context.getResources(); Resources res = context.getResources();
mSize = res.getDimensionPixelSize(R.dimen.badge_size); mSize = (int) (SIZE_PERCENTAGE * iconSizePx);
mCharSize = (int) (CHAR_SIZE_PERCENTAGE * iconSizePx);
mOffset = (int) (OFFSET_PERCENTAGE * iconSizePx);
mTextPaint.setTextSize(iconSizePx * TEXT_SIZE_PERCENTAGE);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mLargeIconDrawer = new IconDrawer(res.getDimensionPixelSize(R.dimen.badge_small_padding)); mLargeIconDrawer = new IconDrawer(res.getDimensionPixelSize(R.dimen.badge_small_padding));
mSmallIconDrawer = new IconDrawer(res.getDimensionPixelSize(R.dimen.badge_large_padding)); mSmallIconDrawer = new IconDrawer(res.getDimensionPixelSize(R.dimen.badge_large_padding));
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setTextSize(res.getDimensionPixelSize(R.dimen.badge_text_size));
mTextPaint.setFakeBoldText(true);
// Measure the text height. // Measure the text height.
Rect tempTextHeight = new Rect(); Rect tempTextHeight = new Rect();
mTextPaint.getTextBounds("0", 0, 1, tempTextHeight); mTextPaint.getTextBounds("0", 0, 1, tempTextHeight);
mTextHeight = tempTextHeight.height(); mTextHeight = tempTextHeight.height();
mBackgroundWithShadow = ShadowGenerator.createCircleWithShadow(Color.WHITE, mSize); mBackgroundsWithShadow = new SparseArray<>(3);
} }
/** /**
@@ -70,29 +82,43 @@ public class BadgeRenderer {
* @param badgeInfo Contains data to draw on the badge. Could be null if we are animating out. * @param badgeInfo Contains data to draw on the badge. Could be null if we are animating out.
* @param iconBounds The bounds of the icon being badged. * @param iconBounds The bounds of the icon being badged.
* @param badgeScale The progress of the animation, from 0 to 1. * @param badgeScale The progress of the animation, from 0 to 1.
* @param spaceForOffset How much space is available to offset the badge up and to the right.
*/ */
public void draw(Canvas canvas, IconPalette palette, @Nullable BadgeInfo badgeInfo, public void draw(Canvas canvas, IconPalette palette, @Nullable BadgeInfo badgeInfo,
Rect iconBounds, float badgeScale) { Rect iconBounds, float badgeScale, Point spaceForOffset) {
mTextPaint.setColor(palette.textColor); mTextPaint.setColor(palette.textColor);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
// We draw the badge relative to its center.
canvas.translate(iconBounds.right - mSize / 2, iconBounds.top + mSize / 2);
canvas.scale(badgeScale, badgeScale);
mBackgroundPaint.setColorFilter(palette.backgroundColorMatrixFilter);
int backgroundSize = mBackgroundWithShadow.getHeight(); // Same as width.
canvas.drawBitmap(mBackgroundWithShadow, -backgroundSize / 2, -backgroundSize / 2,
mBackgroundPaint);
IconDrawer iconDrawer = badgeInfo != null && badgeInfo.isIconLarge() IconDrawer iconDrawer = badgeInfo != null && badgeInfo.isIconLarge()
? mLargeIconDrawer : mSmallIconDrawer; ? mLargeIconDrawer : mSmallIconDrawer;
Shader icon = badgeInfo == null ? null : badgeInfo.getNotificationIconForBadge( Shader icon = badgeInfo == null ? null : badgeInfo.getNotificationIconForBadge(
mContext, palette.backgroundColor, mSize, iconDrawer.mPadding); mContext, palette.backgroundColor, mSize, iconDrawer.mPadding);
String notificationCount = icon != null || badgeInfo == null ? "0"
: String.valueOf(badgeInfo.getNotificationCount());
int numChars = notificationCount.length();
int width = mSize + mCharSize * (numChars - 1);
// Lazily load the background with shadow.
Bitmap backgroundWithShadow = mBackgroundsWithShadow.get(numChars);
if (backgroundWithShadow == null) {
backgroundWithShadow = ShadowGenerator.createPillWithShadow(Color.WHITE, width, mSize);
mBackgroundsWithShadow.put(numChars, backgroundWithShadow);
}
canvas.save(Canvas.MATRIX_SAVE_FLAG);
// We draw the badge relative to its center.
int badgeCenterX = iconBounds.right - width / 2;
int badgeCenterY = iconBounds.top + mSize / 2;
int offsetX = Math.min(mOffset, spaceForOffset.x);
int offsetY = Math.min(mOffset, spaceForOffset.y);
canvas.translate(badgeCenterX + offsetX, badgeCenterY - offsetY);
canvas.scale(badgeScale, badgeScale);
// Draw the background and shadow.
mBackgroundPaint.setColorFilter(palette.backgroundColorMatrixFilter);
int backgroundWithShadowSize = backgroundWithShadow.getHeight(); // Same as width.
canvas.drawBitmap(backgroundWithShadow, -backgroundWithShadowSize / 2,
-backgroundWithShadowSize / 2, mBackgroundPaint);
if (icon != null) { if (icon != null) {
// Draw the notification icon with padding. // Draw the notification icon with padding.
iconDrawer.drawIcon(icon, canvas); iconDrawer.drawIcon(icon, canvas);
} else { } else {
// Draw the notification count. // Draw the notification count.
String notificationCount = badgeInfo == null ? "0"
: String.valueOf(badgeInfo.getNotificationCount());
canvas.drawText(notificationCount, 0, mTextHeight / 2, mTextPaint); canvas.drawText(notificationCount, 0, mTextHeight / 2, mTextPaint);
} }
canvas.restore(); canvas.restore();
@@ -27,6 +27,7 @@ import android.graphics.Color;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Path; import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode; import android.graphics.PorterDuffXfermode;
import android.graphics.RadialGradient; import android.graphics.RadialGradient;
@@ -121,7 +122,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
private PreviewLayoutRule mPreviewLayoutRule; private PreviewLayoutRule mPreviewLayoutRule;
boolean mAnimating = false; boolean mAnimating = false;
private Rect mOldBounds = new Rect(); private Rect mTempBounds = new Rect();
private float mSlop; private float mSlop;
@@ -134,6 +135,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
private FolderBadgeInfo mBadgeInfo = new FolderBadgeInfo(); private FolderBadgeInfo mBadgeInfo = new FolderBadgeInfo();
private BadgeRenderer mBadgeRenderer; private BadgeRenderer mBadgeRenderer;
private float mBadgeScale; private float mBadgeScale;
private Point mTempSpaceForBadgeOffset = new Point();
private static final Property<FolderIcon, Float> BADGE_SCALE_PROPERTY private static final Property<FolderIcon, Float> BADGE_SCALE_PROPERTY
= new Property<FolderIcon, Float>(Float.TYPE, "badgeScale") { = new Property<FolderIcon, Float>(Float.TYPE, "badgeScale") {
@@ -496,7 +498,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
Drawable d = params.drawable; Drawable d = params.drawable;
if (d != null) { if (d != null) {
mOldBounds.set(d.getBounds()); mTempBounds.set(d.getBounds());
d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize); d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
if (d instanceof FastBitmapDrawable) { if (d instanceof FastBitmapDrawable) {
FastBitmapDrawable fd = (FastBitmapDrawable) d; FastBitmapDrawable fd = (FastBitmapDrawable) d;
@@ -507,7 +509,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
d.draw(canvas); d.draw(canvas);
d.clearColorFilter(); d.clearColorFilter();
} }
d.setBounds(mOldBounds); d.setBounds(mTempBounds);
} }
canvas.restore(); canvas.restore();
} }
@@ -878,14 +880,16 @@ public class FolderIcon extends FrameLayout implements FolderListener {
} }
if ((mBadgeInfo != null && mBadgeInfo.getNotificationCount() > 0) || mBadgeScale > 0) { if ((mBadgeInfo != null && mBadgeInfo.getNotificationCount() > 0) || mBadgeScale > 0) {
// If we are animating to the accepting state, animate the badge out.
int offsetX = mBackground.getOffsetX(); int offsetX = mBackground.getOffsetX();
int offsetY = mBackground.getOffsetY(); int offsetY = mBackground.getOffsetY();
int previewSize = (int) (mBackground.previewSize * mBackground.mScale); int previewSize = (int) (mBackground.previewSize * mBackground.mScale);
Rect bounds = new Rect(offsetX, offsetY, offsetX + previewSize, offsetY + previewSize); mTempBounds.set(offsetX, offsetY, offsetX + previewSize, offsetY + previewSize);
// If we are animating to the accepting state, animate the badge out.
float badgeScale = Math.max(0, mBadgeScale - mBackground.getScaleProgress()); float badgeScale = Math.max(0, mBadgeScale - mBackground.getScaleProgress());
mBadgeRenderer.draw(canvas, IconPalette.FOLDER_ICON_PALETTE, mBadgeInfo, bounds, badgeScale); mTempSpaceForBadgeOffset.set(getWidth() - mTempBounds.right, mTempBounds.top);
mBadgeRenderer.draw(canvas, IconPalette.FOLDER_ICON_PALETTE, mBadgeInfo, mTempBounds,
badgeScale, mTempSpaceForBadgeOffset);
} }
} }
@@ -173,12 +173,12 @@ public class IconPalette {
} }
private static int getMutedColor(int color) { private static int getMutedColor(int color) {
int alpha = (int) (255 * 0.15f); int whiteScrim = ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.87f));
return ColorUtils.compositeColors(ColorUtils.setAlphaComponent(color, alpha), Color.WHITE); return ColorUtils.compositeColors(whiteScrim, color);
} }
private static int getTextColorForBackground(int backgroundColor) { private static int getTextColorForBackground(int backgroundColor) {
return getLighterOrDarkerVersionOfColor(backgroundColor, 3f); return getLighterOrDarkerVersionOfColor(backgroundColor, 4.5f);
} }
private static int getLowContrastColor(int color) { private static int getLowContrastColor(int color) {
@@ -83,34 +83,44 @@ public class ShadowGenerator {
return result; return result;
} }
public static Bitmap createCircleWithShadow(int circleColor, int diameter) { public static Bitmap createPillWithShadow(int rectColor, int width, int height) {
float shadowRadius = diameter * 1f / 32; float shadowRadius = height * 1f / 32;
float shadowYOffset = diameter * 1f / 16; float shadowYOffset = height * 1f / 16;
int ambientShadowAlpha = AMBIENT_SHADOW_ALPHA / 2;
int keyShadowAlpha = KEY_SHADOW_ALPHA / 2;
int radius = diameter / 2; int radius = height / 2;
Canvas canvas = new Canvas(); Canvas canvas = new Canvas();
Paint blurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); Paint blurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
blurPaint.setMaskFilter(new BlurMaskFilter(shadowRadius, Blur.NORMAL)); blurPaint.setMaskFilter(new BlurMaskFilter(shadowRadius, Blur.NORMAL));
int center = Math.round(radius + shadowRadius + shadowYOffset); int centerX = Math.round(width / 2 + shadowRadius);
int centerY = Math.round(radius + shadowRadius + shadowYOffset);
int center = Math.max(centerX, centerY);
int size = center * 2; int size = center * 2;
Bitmap result = Bitmap.createBitmap(size, size, Config.ARGB_8888); Bitmap result = Bitmap.createBitmap(size, size, Config.ARGB_8888);
canvas.setBitmap(result); canvas.setBitmap(result);
int left = center - width / 2;
int top = center - height / 2;
int right = center + width / 2;
int bottom = center + height / 2;
// Draw ambient shadow, center aligned within size // Draw ambient shadow, center aligned within size
blurPaint.setAlpha(AMBIENT_SHADOW_ALPHA); blurPaint.setAlpha(ambientShadowAlpha);
canvas.drawCircle(center, center, radius, blurPaint); canvas.drawRoundRect(left, top, right, bottom, radius, radius, blurPaint);
// Draw key shadow, bottom aligned within size // Draw key shadow, bottom aligned within size
blurPaint.setAlpha(KEY_SHADOW_ALPHA); blurPaint.setAlpha(keyShadowAlpha);
canvas.drawCircle(center, center + shadowYOffset, radius, blurPaint); canvas.drawRoundRect(left, top + shadowYOffset, right, bottom + shadowYOffset,
radius, radius, blurPaint);
// Draw the circle // Draw the circle
Paint drawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); Paint drawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
drawPaint.setColor(circleColor); drawPaint.setColor(rectColor);
canvas.drawCircle(center, center, radius, drawPaint); canvas.drawRoundRect(left, top, right, bottom, radius, radius, drawPaint);
return result; return result;
} }
@@ -213,8 +213,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
animateOpen(); animateOpen();
mOriginalIcon = originalIcon; mOriginalIcon = originalIcon;
mLauncher.getDragController().addDragListener(this); mLauncher.getDragController().addDragListener(this);
mOriginalIcon.forceHideBadge(true);
// Load the shortcuts on a background thread and update the container as it animates. // Load the shortcuts on a background thread and update the container as it animates.
final Looper workerLooper = LauncherModel.getWorkerLooper(); final Looper workerLooper = LauncherModel.getWorkerLooper();
@@ -799,6 +799,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}); });
mOpenCloseAnimator = shortcutAnims; mOpenCloseAnimator = shortcutAnims;
shortcutAnims.start(); shortcutAnims.start();
mOriginalIcon.forceHideBadge(false);
} }
/** /**
@@ -814,6 +815,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
boolean isInHotseat = ((ItemInfo) mOriginalIcon.getTag()).container boolean isInHotseat = ((ItemInfo) mOriginalIcon.getTag()).container
== LauncherSettings.Favorites.CONTAINER_HOTSEAT; == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
mOriginalIcon.setTextVisibility(!isInHotseat); mOriginalIcon.setTextVisibility(!isInHotseat);
mOriginalIcon.forceHideBadge(false);
mLauncher.getDragController().removeDragListener(this); mLauncher.getDragController().removeDragListener(this);
mLauncher.getDragLayer().removeView(this); mLauncher.getDragLayer().removeView(this);
} }