summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3
diff options
context:
space:
mode:
authorTony Wickham <twickham@google.com>2017-02-07 22:26:20 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-02-07 22:26:20 +0000
commit4b20e0c312d7a6f5f0a65e8bada74eeb52c15bc0 (patch)
tree5dc32ea9638eb8917587011e877b2b1b11f9ebe7 /src/com/android/launcher3
parent72d90876b8d0403684a534fa65cfbe91c839019b (diff)
parent1e61849bc729858f3fd0c0a1f31b15ef06cffdc3 (diff)
downloadandroid_packages_apps_Trebuchet-4b20e0c312d7a6f5f0a65e8bada74eeb52c15bc0.tar.gz
android_packages_apps_Trebuchet-4b20e0c312d7a6f5f0a65e8bada74eeb52c15bc0.tar.bz2
android_packages_apps_Trebuchet-4b20e0c312d7a6f5f0a65e8bada74eeb52c15bc0.zip
Merge "Animate badges when they are added or removed" into ub-launcher3-master
Diffstat (limited to 'src/com/android/launcher3')
-rw-r--r--src/com/android/launcher3/BubbleTextView.java8
-rw-r--r--src/com/android/launcher3/FastBitmapDrawable.java33
-rw-r--r--src/com/android/launcher3/Workspace.java2
-rw-r--r--src/com/android/launcher3/badge/BadgeRenderer.java66
-rw-r--r--src/com/android/launcher3/folder/FolderIcon.java55
5 files changed, 117 insertions, 47 deletions
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 8043eacdb..bbf2cb8d7 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -167,7 +167,7 @@ public class BubbleTextView extends TextView
applyPromiseState(promiseStateChanged);
}
- applyBadgeState(info);
+ applyBadgeState(info, false /* animate */);
}
public void applyFromApplicationInfo(AppInfo info) {
@@ -179,7 +179,7 @@ public class BubbleTextView extends TextView
// Verify high res immediately
verifyHighRes();
- applyBadgeState(info);
+ applyBadgeState(info, false /* animate */);
}
public void applyFromPackageItemInfo(PackageItemInfo info) {
@@ -501,11 +501,11 @@ public class BubbleTextView extends TextView
}
}
- public void applyBadgeState(ItemInfo itemInfo) {
+ public void applyBadgeState(ItemInfo itemInfo, boolean animate) {
if (mIcon instanceof FastBitmapDrawable) {
BadgeInfo badgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo);
BadgeRenderer badgeRenderer = mLauncher.getDeviceProfile().mBadgeRenderer;
- ((FastBitmapDrawable) mIcon).applyIconBadge(badgeInfo, badgeRenderer);
+ ((FastBitmapDrawable) mIcon).applyIconBadge(badgeInfo, badgeRenderer, animate);
}
}
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 95d2dafce..1f74c8877 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -30,7 +30,7 @@ import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
-import android.util.Log;
+import android.util.Property;
import android.util.SparseArray;
import android.view.animation.DecelerateInterpolator;
@@ -107,6 +107,21 @@ public class FastBitmapDrawable extends Drawable {
private BadgeInfo mBadgeInfo;
private BadgeRenderer mBadgeRenderer;
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();
+ }
+ };
// The saturation and brightness are values that are mapped to REDUCED_FILTER_VALUE_SPACE and
// as a result, can be used to compose the key for the cached ColorMatrixColorFilters
@@ -123,14 +138,22 @@ public class FastBitmapDrawable extends Drawable {
setFilterBitmap(true);
}
- public void applyIconBadge(BadgeInfo badgeInfo, BadgeRenderer badgeRenderer) {
+ 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();
- invalidateSelf();
+ // 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();
+ }
}
}
@@ -154,7 +177,7 @@ public class FastBitmapDrawable extends Drawable {
protected void drawBadgeIfNecessary(Canvas canvas) {
if (hasBadge()) {
- mBadgeRenderer.draw(canvas, mIconPalette, mBadgeInfo, getBounds());
+ mBadgeRenderer.draw(canvas, mIconPalette, mBadgeInfo, getBounds(), mBadgeScale);
}
}
@@ -167,7 +190,7 @@ public class FastBitmapDrawable extends Drawable {
}
private boolean hasBadge() {
- return mBadgeInfo != null && mBadgeInfo.getNotificationCount() != 0;
+ return (mBadgeInfo != null && mBadgeInfo.getNotificationCount() > 0) || mBadgeScale > 0;
}
@Override
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index cd74ed96f..3aa882587 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -3993,7 +3993,7 @@ public class Workspace extends PagedView
if (info instanceof ShortcutInfo && v instanceof BubbleTextView
&& packageUserKey.updateFromItemInfo(info)) {
if (updatedBadges.contains(packageUserKey)) {
- ((BubbleTextView) v).applyBadgeState(info);
+ ((BubbleTextView) v).applyBadgeState(info, true /* animate */);
folderIds.add(info.container);
}
}
diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java
index 4bb09546f..8bbc2afa2 100644
--- a/src/com/android/launcher3/badge/BadgeRenderer.java
+++ b/src/com/android/launcher3/badge/BadgeRenderer.java
@@ -24,6 +24,7 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
+import android.support.annotation.Nullable;
import com.android.launcher3.R;
import com.android.launcher3.graphics.IconPalette;
@@ -34,62 +35,59 @@ import com.android.launcher3.graphics.IconPalette;
*/
public class BadgeRenderer {
- public int size;
- public int textSize;
- public IconDrawer largeIconDrawer;
- public IconDrawer smallIconDrawer;
-
private final Context mContext;
- private final RectF mBackgroundRect = new RectF();
+ private final int mSize;
+ private final int mTextHeight;
+ private final IconDrawer mLargeIconDrawer;
+ private final IconDrawer mSmallIconDrawer;
private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- private final int mTextHeight;
public BadgeRenderer(Context context) {
mContext = context;
Resources res = context.getResources();
- size = res.getDimensionPixelSize(R.dimen.badge_size);
- textSize = res.getDimensionPixelSize(R.dimen.badge_text_size);
- largeIconDrawer = new IconDrawer(res.getDimensionPixelSize(R.dimen.badge_small_padding));
- smallIconDrawer = new IconDrawer(res.getDimensionPixelSize(R.dimen.badge_large_padding));
+ mSize = res.getDimensionPixelSize(R.dimen.badge_size);
+ mLargeIconDrawer = new IconDrawer(res.getDimensionPixelSize(R.dimen.badge_small_padding));
+ mSmallIconDrawer = new IconDrawer(res.getDimensionPixelSize(R.dimen.badge_large_padding));
mTextPaint.setTextAlign(Paint.Align.CENTER);
- mTextPaint.setTextSize(textSize);
+ mTextPaint.setTextSize(res.getDimensionPixelSize(R.dimen.badge_text_size));
// Measure the text height.
- Rect temp = new Rect();
- mTextPaint.getTextBounds("0", 0, 1, temp);
- mTextHeight = temp.height();
+ Rect tempTextHeight = new Rect();
+ mTextPaint.getTextBounds("0", 0, 1, tempTextHeight);
+ mTextHeight = tempTextHeight.height();
}
/**
* Draw a circle in the top right corner of the given bounds, and draw
* {@link BadgeInfo#getNotificationCount()} on top of the circle.
* @param palette The colors (based on the icon) to use for the badge.
- * @param badgeInfo Contains data to draw on the badge.
+ * @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 badgeScale The progress of the animation, from 0 to 1.
*/
- public void draw(Canvas canvas, IconPalette palette, BadgeInfo badgeInfo, Rect iconBounds) {
+ public void draw(Canvas canvas, IconPalette palette, @Nullable BadgeInfo badgeInfo,
+ Rect iconBounds, float badgeScale) {
mBackgroundPaint.setColor(palette.backgroundColor);
mTextPaint.setColor(palette.textColor);
- mBackgroundRect.set(iconBounds.right - size, iconBounds.top, iconBounds.right,
- iconBounds.top + size);
- canvas.drawOval(mBackgroundRect, mBackgroundPaint);
- IconDrawer iconDrawer = badgeInfo.isIconLarge() ? largeIconDrawer : smallIconDrawer;
- Shader icon = badgeInfo.getNotificationIconForBadge(mContext, palette.backgroundColor, size,
- iconDrawer.mPadding);
+ 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);
+ canvas.drawCircle(0, 0, mSize / 2, mBackgroundPaint);
+ IconDrawer iconDrawer = badgeInfo != null && badgeInfo.isIconLarge()
+ ? mLargeIconDrawer : mSmallIconDrawer;
+ Shader icon = badgeInfo == null ? null : badgeInfo.getNotificationIconForBadge(
+ mContext, palette.backgroundColor, mSize, iconDrawer.mPadding);
if (icon != null) {
// Draw the notification icon with padding.
- canvas.save();
- canvas.translate(mBackgroundRect.left, mBackgroundRect.top);
iconDrawer.drawIcon(icon, canvas);
- canvas.restore();
} else {
// Draw the notification count.
- String notificationCount = String.valueOf(badgeInfo.getNotificationCount());
- canvas.drawText(notificationCount,
- mBackgroundRect.centerX(),
- mBackgroundRect.centerY() + mTextHeight / 2,
- mTextPaint);
+ String notificationCount = badgeInfo == null ? "0"
+ : String.valueOf(badgeInfo.getNotificationCount());
+ canvas.drawText(notificationCount, 0, mTextHeight / 2, mTextPaint);
}
+ canvas.restore();
}
/** Draws the notification icon with padding of a given size. */
@@ -102,15 +100,15 @@ public class BadgeRenderer {
public IconDrawer(int padding) {
mPadding = padding;
- mCircleClipBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ALPHA_8);
+ mCircleClipBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ALPHA_8);
Canvas canvas = new Canvas();
canvas.setBitmap(mCircleClipBitmap);
- canvas.drawCircle(size / 2, size / 2, size / 2 - padding, mPaint);
+ canvas.drawCircle(mSize / 2, mSize / 2, mSize / 2 - padding, mPaint);
}
public void drawIcon(Shader icon, Canvas canvas) {
mPaint.setShader(icon);
- canvas.drawBitmap(mCircleClipBitmap, 0f, 0f, mPaint);
+ canvas.drawBitmap(mCircleClipBitmap, -mSize / 2, -mSize / 2, mPaint);
mPaint.setShader(null);
}
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 171d40d5c..96d56759d 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -33,6 +33,7 @@ import android.graphics.drawable.Drawable;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.Property;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -130,6 +131,21 @@ public class FolderIcon extends FrameLayout implements FolderListener {
private FolderBadgeInfo mBadgeInfo = new FolderBadgeInfo();
private BadgeRenderer mBadgeRenderer;
+ private float mBadgeScale;
+
+ private static final Property<FolderIcon, Float> BADGE_SCALE_PROPERTY
+ = new Property<FolderIcon, Float>(Float.TYPE, "badgeScale") {
+ @Override
+ public Float get(FolderIcon folderIcon) {
+ return folderIcon.mBadgeScale;
+ }
+
+ @Override
+ public void set(FolderIcon folderIcon, Float value) {
+ folderIcon.mBadgeScale = value;
+ folderIcon.invalidate();
+ }
+ };
public FolderIcon(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -388,8 +404,25 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
public void setBadgeInfo(FolderBadgeInfo badgeInfo) {
+ updateBadgeScale(mBadgeInfo.getNotificationCount(), badgeInfo.getNotificationCount());
mBadgeInfo = badgeInfo;
- invalidate();
+ }
+
+ /**
+ * Sets mBadgeScale to 1 or 0, animating if oldCount or newCount is 0
+ * (the badge is being added or removed).
+ */
+ private void updateBadgeScale(int oldCount, int newCount) {
+ boolean wasBadged = oldCount > 0;
+ boolean isBadged = newCount > 0;
+ float newBadgeScale = isBadged ? 1f : 0f;
+ // Animate when a badge is first added or when it is removed.
+ if ((wasBadged ^ isBadged) && isShown()) {
+ ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, newBadgeScale).start();
+ } else {
+ mBadgeScale = newBadgeScale;
+ invalidate();
+ }
}
static class PreviewItemDrawingParams {
@@ -550,6 +583,14 @@ public class FolderIcon extends FrameLayout implements FolderListener {
return basePreviewOffsetY - (getScaledRadius() - getRadius());
}
+ /**
+ * Returns the progress of the scale animation, where 0 means the scale is at 1f
+ * and 1 means the scale is at ACCEPT_SCALE_FACTOR.
+ */
+ float getScaleProgress() {
+ return (mScale - 1f) / (ACCEPT_SCALE_FACTOR - 1f);
+ }
+
void invalidate() {
int radius = getScaledRadius();
mClipPath.reset();
@@ -785,8 +826,10 @@ public class FolderIcon extends FrameLayout implements FolderListener {
int offsetY = mBackground.getOffsetY();
int previewSize = (int) (mBackground.previewSize * mBackground.mScale);
Rect bounds = new Rect(offsetX, offsetY, offsetX + previewSize, offsetY + previewSize);
- if (mBadgeInfo != null && mBadgeInfo.getNotificationCount() > 0) {
- mBadgeRenderer.draw(canvas, IconPalette.FOLDER_ICON_PALETTE, mBadgeInfo, bounds);
+ if ((mBadgeInfo != null && mBadgeInfo.getNotificationCount() > 0) || mBadgeScale > 0) {
+ // If we are animating to the accepting state, animate the badge out.
+ float badgeScale = Math.max(0, mBadgeScale - mBackground.getScaleProgress());
+ mBadgeRenderer.draw(canvas, IconPalette.FOLDER_ICON_PALETTE, mBadgeInfo, bounds, badgeScale);
}
}
@@ -939,14 +982,20 @@ public class FolderIcon extends FrameLayout implements FolderListener {
@Override
public void onAdd(ShortcutInfo item) {
+ int oldCount = mBadgeInfo.getNotificationCount();
mBadgeInfo.addBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item));
+ int newCount = mBadgeInfo.getNotificationCount();
+ updateBadgeScale(oldCount, newCount);
invalidate();
requestLayout();
}
@Override
public void onRemove(ShortcutInfo item) {
+ int oldCount = mBadgeInfo.getNotificationCount();
mBadgeInfo.subtractBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item));
+ int newCount = mBadgeInfo.getNotificationCount();
+ updateBadgeScale(oldCount, newCount);
invalidate();
requestLayout();
}