Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1237df0a authored by Tony Wickham's avatar Tony Wickham
Browse files

Update icon badges to match spec

- Size defined as percentage of app icon size
- Width changes when there are 2 or 3 digits (round rect)
- Offset slightly away from the app icon
  - Had to move drawing to BubbleTextView instead of
    FastBitmapDrawable
- Hide badge when dragging and while popup is open
- Tweaks for some color/text parameters

Bug: 35744066
Change-Id: Ibb15ca634abaa0729aea637c904c4c6889a58c7c
parent 343a77e6
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -182,8 +182,6 @@
    <dimen name="system_shortcut_header_icon_padding">12dp</dimen>

<!-- 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_large_padding">3dp</dimen>

+89 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.launcher3;

import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -23,9 +24,12 @@ import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Property;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -42,6 +46,7 @@ import com.android.launcher3.badge.BadgeRenderer;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.HolographicOutlineHelper;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
@@ -90,6 +95,28 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
    @ViewDebug.ExportedProperty(category = "launcher")
    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")
    private boolean mStayPressed;
    @ViewDebug.ExportedProperty(category = "launcher")
@@ -369,6 +396,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
    public void draw(Canvas canvas) {
        if (!mCustomShadowsEnabled) {
            super.draw(canvas);
            drawBadgeIfNecessary(canvas);
            return;
        }

@@ -395,6 +423,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
        if ((getCurrentTextColor() >> 24) == 0) {
            getPaint().clearShadowLayer();
            super.draw(canvas);
            drawBadgeIfNecessary(canvas);
            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);
        super.draw(canvas);
        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
@@ -506,7 +579,22 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
            if (popup != null) {
                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
Original line number Diff line number Diff line
@@ -197,8 +197,6 @@ public class DeviceProfile {
        hotseatBarBottomPaddingPx = 0;
        hotseatLandGutterPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_gutter_width);

        mBadgeRenderer = new BadgeRenderer(context);

        // Determine sizes.
        widthPx = width;
        heightPx = height;
@@ -213,6 +211,9 @@ public class DeviceProfile {
        // Calculate the remaining vars
        updateAvailableDimensions(dm, res);
        computeAllAppsButtonSize(context);

        // This is done last, after iconSizePx is calculated above.
        mBadgeRenderer = new BadgeRenderer(context, iconSizePx);
    }

    DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
+0 −50
Original line number Diff line number Diff line
@@ -32,8 +32,6 @@ import android.graphics.drawable.Drawable;
import android.util.Property;
import android.util.SparseArray;

import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.badge.BadgeRenderer;
import com.android.launcher3.graphics.IconPalette;

public class FastBitmapDrawable extends Drawable {
@@ -77,24 +75,7 @@ public class FastBitmapDrawable extends Drawable {
    private boolean mIsPressed;
    private boolean mIsDisabled;

    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();
        }
    };

    private static final Property<FastBitmapDrawable, Float> BRIGHTNESS
            = new Property<FastBitmapDrawable, Float>(Float.TYPE, "brightness") {
@@ -124,30 +105,9 @@ public class FastBitmapDrawable extends Drawable {
        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
    public void draw(Canvas canvas) {
        drawInternal(canvas);
        // Draw the icon badge in the top right corner.
        drawBadgeIfNecessary(canvas);
    }

    public void drawWithBrightness(Canvas canvas, float brightness) {
@@ -161,12 +121,6 @@ public class FastBitmapDrawable extends Drawable {
        canvas.drawBitmap(mBitmap, null, getBounds(), mPaint);
    }

    protected void drawBadgeIfNecessary(Canvas canvas) {
        if (hasBadge()) {
            mBadgeRenderer.draw(canvas, mIconPalette, mBadgeInfo, getBounds(), mBadgeScale);
        }
    }

    public IconPalette getIconPalette() {
        if (mIconPalette == null) {
            mIconPalette = IconPalette.fromDominantColor(Utilities
@@ -175,10 +129,6 @@ public class FastBitmapDrawable extends Drawable {
        return mIconPalette;
    }

    private boolean hasBadge() {
        return (mBadgeInfo != null && mBadgeInfo.getNotificationCount() > 0) || mBadgeScale > 0;
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        // No op
+4 −8
Original line number Diff line number Diff line
@@ -2247,16 +2247,12 @@ public class Workspace extends PagedView
        Point dragVisualizeOffset = null;
        Rect dragRect = null;
        if (child instanceof BubbleTextView) {
            int iconSize = grid.iconSizePx;
            int top = child.getPaddingTop();
            int left = (b.getWidth() - iconSize) / 2;
            int right = left + iconSize;
            int bottom = top + iconSize;
            dragLayerY += top;
            // Note: The drag region is used to calculate drag layer offsets, but the
            dragRect = new Rect();
            ((BubbleTextView) child).getIconBounds(dragRect);
            dragLayerY += dragRect.top;
            // Note: The dragRect is used to calculate drag layer offsets, but the
            // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
            dragVisualizeOffset = new Point(- halfPadding, halfPadding);
            dragRect = new Rect(left, top, right, bottom);
        } else if (child instanceof FolderIcon) {
            int previewSize = grid.folderIconSizePx;
            dragVisualizeOffset = new Point(- halfPadding, halfPadding - child.getPaddingTop());
Loading