diff options
8 files changed, 96 insertions, 45 deletions
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 24d16d7e5..cb40d3d5e 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -473,7 +473,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver { } private boolean hasBadge() { - return (mBadgeInfo != null && mBadgeInfo.getNotificationCount() > 0); + return mBadgeInfo != null; } public void getIconBounds(Rect outBounds) { diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java index a1ef22f4e..2971ceb80 100644 --- a/src/com/android/launcher3/badge/BadgeRenderer.java +++ b/src/com/android/launcher3/badge/BadgeRenderer.java @@ -44,12 +44,17 @@ public class BadgeRenderer { 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 static final float STACK_OFFSET_PERCENTAGE_X = 0.05f; + private static final float STACK_OFFSET_PERCENTAGE_Y = 0.06f; + private static final float DOT_SCALE = 0.6f; private final Context mContext; private final int mSize; private final int mCharSize; private final int mTextHeight; private final int mOffset; + private final int mStackOffsetX; + private final int mStackOffsetY; private final IconDrawer mLargeIconDrawer; private final IconDrawer mSmallIconDrawer; private final Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -63,6 +68,8 @@ public class BadgeRenderer { mSize = (int) (SIZE_PERCENTAGE * iconSizePx); mCharSize = (int) (CHAR_SIZE_PERCENTAGE * iconSizePx); mOffset = (int) (OFFSET_PERCENTAGE * iconSizePx); + mStackOffsetX = (int) (STACK_OFFSET_PERCENTAGE_X * iconSizePx); + mStackOffsetY = (int) (STACK_OFFSET_PERCENTAGE_Y * iconSizePx); mTextPaint.setTextSize(iconSizePx * TEXT_SIZE_PERCENTAGE); mTextPaint.setTextAlign(Paint.Align.CENTER); mLargeIconDrawer = new IconDrawer(res.getDimensionPixelSize(R.dimen.badge_small_padding)); @@ -91,7 +98,7 @@ public class BadgeRenderer { ? mLargeIconDrawer : mSmallIconDrawer; Shader icon = badgeInfo == null ? null : badgeInfo.getNotificationIconForBadge( mContext, palette.backgroundColor, mSize, iconDrawer.mPadding); - String notificationCount = icon != null || badgeInfo == null ? "0" + String notificationCount = badgeInfo == null ? "0" : String.valueOf(badgeInfo.getNotificationCount()); int numChars = notificationCount.length(); int width = mSize + mCharSize * (numChars - 1); @@ -105,21 +112,42 @@ public class BadgeRenderer { // We draw the badge relative to its center. int badgeCenterX = iconBounds.right - width / 2; int badgeCenterY = iconBounds.top + mSize / 2; + boolean isText = badgeInfo != null && badgeInfo.getNotificationCount() != 0; + boolean isIcon = icon != null; + boolean isDot = !(isText || isIcon); + if (isDot) { + badgeScale *= DOT_SCALE; + } 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. + // Prepare the background and shadow and possible stacking effect. mBackgroundPaint.setColorFilter(palette.backgroundColorMatrixFilter); int backgroundWithShadowSize = backgroundWithShadow.getHeight(); // Same as width. - canvas.drawBitmap(backgroundWithShadow, -backgroundWithShadowSize / 2, - -backgroundWithShadowSize / 2, mBackgroundPaint); - if (icon != null) { - // Draw the notification icon with padding. - iconDrawer.drawIcon(icon, canvas); - } else { - // Draw the notification count. + boolean shouldStack = !isDot && badgeInfo != null + && badgeInfo.getNotificationKeys().size() > 1; + if (shouldStack) { + int offsetDiffX = mStackOffsetX - mOffset; + int offsetDiffY = mStackOffsetY - mOffset; + canvas.translate(offsetDiffX, offsetDiffY); + canvas.drawBitmap(backgroundWithShadow, -backgroundWithShadowSize / 2, + -backgroundWithShadowSize / 2, mBackgroundPaint); + canvas.translate(-offsetDiffX, -offsetDiffY); + } + + if (isText) { + canvas.drawBitmap(backgroundWithShadow, -backgroundWithShadowSize / 2, + -backgroundWithShadowSize / 2, mBackgroundPaint); canvas.drawText(notificationCount, 0, mTextHeight / 2, mTextPaint); + } else if (isIcon) { + canvas.drawBitmap(backgroundWithShadow, -backgroundWithShadowSize / 2, + -backgroundWithShadowSize / 2, mBackgroundPaint); + iconDrawer.drawIcon(icon, canvas); + } else if (isDot) { + mBackgroundPaint.setColorFilter(palette.saturatedBackgroundColorMatrixFilter); + canvas.drawBitmap(backgroundWithShadow, -backgroundWithShadowSize / 2, + -backgroundWithShadowSize / 2, mBackgroundPaint); } canvas.restore(); } diff --git a/src/com/android/launcher3/badge/FolderBadgeInfo.java b/src/com/android/launcher3/badge/FolderBadgeInfo.java index f7c64aa88..3a1bf60c4 100644 --- a/src/com/android/launcher3/badge/FolderBadgeInfo.java +++ b/src/com/android/launcher3/badge/FolderBadgeInfo.java @@ -19,14 +19,14 @@ package com.android.launcher3.badge; import com.android.launcher3.Utilities; /** - * Subclass of BadgeInfo that only contains the badge count, - * which is the sum of all the Folder's items' counts. + * Subclass of BadgeInfo that only contains the badge count, which is + * the sum of all the Folder's items' notifications (each counts as 1). */ public class FolderBadgeInfo extends BadgeInfo { private static final int MIN_COUNT = 0; - private int mTotalNotificationCount; + private int mNumNotifications; public FolderBadgeInfo() { super(null); @@ -36,22 +36,27 @@ public class FolderBadgeInfo extends BadgeInfo { if (badgeToAdd == null) { return; } - mTotalNotificationCount += badgeToAdd.getNotificationCount(); - mTotalNotificationCount = Utilities.boundToRange( - mTotalNotificationCount, MIN_COUNT, BadgeInfo.MAX_COUNT); + mNumNotifications += badgeToAdd.getNotificationKeys().size(); + mNumNotifications = Utilities.boundToRange( + mNumNotifications, MIN_COUNT, BadgeInfo.MAX_COUNT); } public void subtractBadgeInfo(BadgeInfo badgeToSubtract) { if (badgeToSubtract == null) { return; } - mTotalNotificationCount -= badgeToSubtract.getNotificationCount(); - mTotalNotificationCount = Utilities.boundToRange( - mTotalNotificationCount, MIN_COUNT, BadgeInfo.MAX_COUNT); + mNumNotifications -= badgeToSubtract.getNotificationKeys().size(); + mNumNotifications = Utilities.boundToRange( + mNumNotifications, MIN_COUNT, BadgeInfo.MAX_COUNT); } @Override public int getNotificationCount() { - return mTotalNotificationCount; + // This forces the folder badge to always show up as a dot. + return 0; + } + + public boolean hasBadge() { + return mNumNotifications > 0; } } diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index c78925c58..25123fb1d 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -403,17 +403,15 @@ public class FolderIcon extends FrameLayout implements FolderListener { } public void setBadgeInfo(FolderBadgeInfo badgeInfo) { - updateBadgeScale(mBadgeInfo.getNotificationCount(), badgeInfo.getNotificationCount()); + updateBadgeScale(mBadgeInfo.hasBadge(), badgeInfo.hasBadge()); mBadgeInfo = badgeInfo; } /** - * Sets mBadgeScale to 1 or 0, animating if oldCount or newCount is 0 + * Sets mBadgeScale to 1 or 0, animating if wasBadged or isBadged is false * (the badge is being added or removed). */ - private void updateBadgeScale(int oldCount, int newCount) { - boolean wasBadged = oldCount > 0; - boolean isBadged = newCount > 0; + private void updateBadgeScale(boolean wasBadged, boolean isBadged) { float newBadgeScale = isBadged ? 1f : 0f; // Animate when a badge is first added or when it is removed. if ((wasBadged ^ isBadged) && isShown()) { @@ -879,7 +877,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { mBackground.drawBackgroundStroke(canvas); } - if ((mBadgeInfo != null && mBadgeInfo.getNotificationCount() > 0) || mBadgeScale > 0) { + if ((mBadgeInfo != null && mBadgeInfo.hasBadge()) || mBadgeScale > 0) { int offsetX = mBackground.getOffsetX(); int offsetY = mBackground.getOffsetY(); int previewSize = (int) (mBackground.previewSize * mBackground.mScale); @@ -1046,20 +1044,20 @@ public class FolderIcon extends FrameLayout implements FolderListener { @Override public void onAdd(ShortcutInfo item) { - int oldCount = mBadgeInfo.getNotificationCount(); + boolean wasBadged = mBadgeInfo.hasBadge(); mBadgeInfo.addBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item)); - int newCount = mBadgeInfo.getNotificationCount(); - updateBadgeScale(oldCount, newCount); + boolean isBadged = mBadgeInfo.hasBadge(); + updateBadgeScale(wasBadged, isBadged); invalidate(); requestLayout(); } @Override public void onRemove(ShortcutInfo item) { - int oldCount = mBadgeInfo.getNotificationCount(); + boolean wasBadged = mBadgeInfo.hasBadge(); mBadgeInfo.subtractBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item)); - int newCount = mBadgeInfo.getNotificationCount(); - updateBadgeScale(oldCount, newCount); + boolean isBadged = mBadgeInfo.hasBadge(); + updateBadgeScale(wasBadged, isBadged); invalidate(); requestLayout(); } diff --git a/src/com/android/launcher3/graphics/IconPalette.java b/src/com/android/launcher3/graphics/IconPalette.java index c45f48190..1212cba05 100644 --- a/src/com/android/launcher3/graphics/IconPalette.java +++ b/src/com/android/launcher3/graphics/IconPalette.java @@ -43,6 +43,7 @@ public class IconPalette { public final int dominantColor; public final int backgroundColor; public final ColorMatrixColorFilter backgroundColorMatrixFilter; + public final ColorMatrixColorFilter saturatedBackgroundColorMatrixFilter; public final int textColor; public final int secondaryColor; @@ -52,6 +53,9 @@ public class IconPalette { ColorMatrix backgroundColorMatrix = new ColorMatrix(); Themes.setColorScaleOnMatrix(backgroundColor, backgroundColorMatrix); backgroundColorMatrixFilter = new ColorMatrixColorFilter(backgroundColorMatrix); + // Get slightly more saturated background color. + Themes.setColorScaleOnMatrix(getMutedColor(dominantColor, 0.54f), backgroundColorMatrix); + saturatedBackgroundColorMatrixFilter = new ColorMatrixColorFilter(backgroundColorMatrix); textColor = getTextColorForBackground(backgroundColor); secondaryColor = getLowContrastColor(backgroundColor); } @@ -173,7 +177,11 @@ public class IconPalette { } private static int getMutedColor(int color) { - int whiteScrim = ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.87f)); + return getMutedColor(color, 0.87f); + } + + private static int getMutedColor(int color, float whiteScrimAlpha) { + int whiteScrim = ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * whiteScrimAlpha)); return ColorUtils.compositeColors(whiteScrim, color); } diff --git a/src/com/android/launcher3/notification/NotificationKeyData.java b/src/com/android/launcher3/notification/NotificationKeyData.java index bf7ae1a5c..154ea216b 100644 --- a/src/com/android/launcher3/notification/NotificationKeyData.java +++ b/src/com/android/launcher3/notification/NotificationKeyData.java @@ -37,7 +37,7 @@ public class NotificationKeyData { private NotificationKeyData(String notificationKey, String shortcutId, int count) { this.notificationKey = notificationKey; this.shortcutId = shortcutId; - this.count = Math.max(1, count); + this.count = count; } public static NotificationKeyData fromNotification(StatusBarNotification sbn) { diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index b00eb1f72..deab3d96d 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -562,6 +562,11 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra } private void updateNotificationHeader() { + if (true) { + // For now, don't show any number in the popup. + // TODO: determine whether a number makes sense, and if not, remove associated code. + return; + } ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag(); BadgeInfo badgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo); if (mNotificationItemView != null && badgeInfo != null) { @@ -578,7 +583,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra } ItemInfo originalInfo = (ItemInfo) mOriginalIcon.getTag(); BadgeInfo badgeInfo = updatedBadges.get(PackageUserKey.fromItemInfo(originalInfo)); - if (badgeInfo == null || badgeInfo.getNotificationCount() == 0) { + if (badgeInfo == null || badgeInfo.getNotificationKeys().size() == 0) { AnimatorSet removeNotification = LauncherAnimUtils.createAnimatorSet(); final int duration = getResources().getInteger( R.integer.config_removeNotificationViewDuration); diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java index eaceaa959..de9f25e12 100644 --- a/src/com/android/launcher3/popup/PopupDataProvider.java +++ b/src/com/android/launcher3/popup/PopupDataProvider.java @@ -84,7 +84,7 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan badgeShouldBeRefreshed = shouldBeFilteredOut ? badgeInfo.removeNotificationKey(notificationKey) : badgeInfo.addOrUpdateNotificationKey(notificationKey); - if (badgeInfo.getNotificationCount() == 0) { + if (badgeInfo.getNotificationKeys().size() == 0) { mPackageUserToBadgeInfos.remove(postedPackageUserKey); } } @@ -97,7 +97,7 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan NotificationKeyData notificationKey) { BadgeInfo oldBadgeInfo = mPackageUserToBadgeInfos.get(removedPackageUserKey); if (oldBadgeInfo != null && oldBadgeInfo.removeNotificationKey(notificationKey)) { - if (oldBadgeInfo.getNotificationCount() == 0) { + if (oldBadgeInfo.getNotificationKeys().size() == 0) { mPackageUserToBadgeInfos.remove(removedPackageUserKey); } updateLauncherIconBadges(Utilities.singletonHashSet(removedPackageUserKey)); @@ -187,14 +187,21 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan boolean hadNotificationToShow = badgeInfo.hasNotificationToShow(); NotificationInfo notificationInfo = null; NotificationListener notificationListener = NotificationListener.getInstanceIfConnected(); - if (notificationListener != null && badgeInfo.getNotificationKeys().size() == 1) { - String onlyNotificationKey = badgeInfo.getNotificationKeys().get(0).notificationKey; - StatusBarNotification[] activeNotifications = notificationListener - .getActiveNotifications(new String[] {onlyNotificationKey}); - if (activeNotifications.length == 1) { - notificationInfo = new NotificationInfo(mLauncher, activeNotifications[0]); - if (!notificationInfo.shouldShowIconInBadge()) { - notificationInfo = null; + if (notificationListener != null && badgeInfo.getNotificationKeys().size() >= 1) { + // Look for the most recent notification that has an icon that should be shown in badge. + for (NotificationKeyData notificationKeyData : badgeInfo.getNotificationKeys()) { + String notificationKey = notificationKeyData.notificationKey; + StatusBarNotification[] activeNotifications = notificationListener + .getActiveNotifications(new String[]{notificationKey}); + if (activeNotifications.length == 1) { + notificationInfo = new NotificationInfo(mLauncher, activeNotifications[0]); + if (notificationInfo.shouldShowIconInBadge()) { + // Found an appropriate icon. + break; + } else { + // Keep looking. + notificationInfo = null; + } } } } |