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

Commit dec75d5a authored by Sunny Goyal's avatar Sunny Goyal Committed by android-build-merger
Browse files

Merge "Updating FolderIcon drawing to avoid dependency on software layer." into ub-launcher3-dorval

am: 3ba48fa0

Change-Id: Id18f5a34264411582115cde8cddd0dc8ecded8df
parents cefc07ed 3ba48fa0
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -105,7 +105,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {

    private ArrayList<FolderIcon.PreviewBackground> mFolderBackgrounds = new ArrayList<FolderIcon.PreviewBackground>();
    FolderIcon.PreviewBackground mFolderLeaveBehind = new FolderIcon.PreviewBackground();
    Paint mFolderBgPaint = new Paint();

    private float mBackgroundAlpha;

@@ -501,9 +500,9 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
            cellToPoint(bg.delegateCellX, bg.delegateCellY, mTempLocation);
            canvas.save();
            canvas.translate(mTempLocation[0], mTempLocation[1]);
            bg.drawBackground(canvas, mFolderBgPaint);
            bg.drawBackground(canvas);
            if (!bg.isClipping) {
                bg.drawBackgroundStroke(canvas, mFolderBgPaint);
                bg.drawBackgroundStroke(canvas);
            }
            canvas.restore();
        }
@@ -513,7 +512,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
                    mFolderLeaveBehind.delegateCellY, mTempLocation);
            canvas.save();
            canvas.translate(mTempLocation[0], mTempLocation[1]);
            mFolderLeaveBehind.drawLeaveBehind(canvas, mFolderBgPaint);
            mFolderLeaveBehind.drawLeaveBehind(canvas);
            canvas.restore();
        }
    }
@@ -528,7 +527,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
                cellToPoint(bg.delegateCellX, bg.delegateCellY, mTempLocation);
                canvas.save();
                canvas.translate(mTempLocation[0], mTempLocation[1]);
                bg.drawBackgroundStroke(canvas, mFolderBgPaint);
                bg.drawBackgroundStroke(canvas);
                canvas.restore();
            }
        }
+128 −72
Original line number Diff line number Diff line
@@ -24,11 +24,15 @@ import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -126,8 +130,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
    private ArrayList<PreviewItemDrawingParams> mDrawingParams = new ArrayList<PreviewItemDrawingParams>();
    private Drawable mReferenceDrawable = null;

    Paint mBgPaint = new Paint();

    private Alarm mOpenAlarm = new Alarm();

    private FolderBadgeInfo mBadgeInfo = new FolderBadgeInfo();
@@ -180,11 +182,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
        DeviceProfile grid = launcher.getDeviceProfile();
        FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);

        // For performance and compatibility reasons we render the preview using a software layer.
        // In particular, hardware path clipping has spotty ecosystem support and bad performance.
        // Software rendering also allows us to use shadow layers.
        icon.setLayerType(LAYER_TYPE_SOFTWARE, new Paint(Paint.FILTER_BITMAP_FLAG));

        icon.setClipToPadding(false);
        icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name);
        icon.mFolderName.setText(folderInfo.title);
@@ -495,7 +492,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
    }

    private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
        canvas.save();
        canvas.save(Canvas.MATRIX_SAVE_FLAG);
        canvas.translate(params.transX, params.transY);
        canvas.scale(params.scale, params.scale);
        Drawable d = params.drawable;
@@ -522,10 +519,29 @@ public class FolderIcon extends FrameLayout implements FolderListener {
     * information, handles drawing, and animation (accept state <--> rest state).
     */
    public static class PreviewBackground {

        private final PorterDuffXfermode mClipPorterDuffXfermode
                = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
        // Create a RadialGradient such that it draws a black circle and then extends with
        // transparent. To achieve this, we keep the gradient to black for the range [0, 1) and
        // just at the edge quickly change it to transparent.
        private final RadialGradient mClipShader = new RadialGradient(0, 0, 1,
                new int[] {Color.BLACK, Color.BLACK, Color.TRANSPARENT },
                new float[] {0, 0.999f, 1},
                Shader.TileMode.CLAMP);

        private final PorterDuffXfermode mShadowPorterDuffXfermode
                = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
        private RadialGradient mShadowShader = null;

        private final Matrix mShaderMatrix = new Matrix();
        private final Path mPath = new Path();

        private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        private float mScale = 1f;
        private float mColorMultiplier = 1f;
        private Path mClipPath = new Path();
        private int mStrokeWidth;
        private float mStrokeWidth;
        private View mInvalidateDelegate;

        public int previewSize;
@@ -548,7 +564,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
        private static final int BG_OPACITY = 160;
        private static final int MAX_BG_OPACITY = 225;
        private static final int BG_INTENSITY = 245;
        private static final int SHADOW_OPACITY = 80;
        private static final int SHADOW_OPACITY = 40;

        ValueAnimator mScaleAnimator;

@@ -564,7 +580,16 @@ public class FolderIcon extends FrameLayout implements FolderListener {
            basePreviewOffsetX = (availableSpace - this.previewSize) / 2;
            basePreviewOffsetY = previewPadding + grid.folderBackgroundOffset + topPadding;

            mStrokeWidth = Utilities.pxFromDp(1, dm);
            // Stroke width is 1dp
            mStrokeWidth = dm.density;

            float radius = getScaledRadius();
            float shadowRadius = radius + mStrokeWidth;
            int shadowColor = Color.argb(SHADOW_OPACITY, 0, 0, 0);
            mShadowShader = new RadialGradient(0, 0, 1,
                    new int[] {shadowColor, Color.TRANSPARENT},
                    new float[] {radius / shadowRadius, 1},
                    Shader.TileMode.CLAMP);

            invalidate();
        }
@@ -594,10 +619,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
        }

        void invalidate() {
            int radius = getScaledRadius();
            mClipPath.reset();
            mClipPath.addCircle(radius, radius, radius, Path.Direction.CW);

            if (mInvalidateDelegate != null) {
                mInvalidateDelegate.invalidate();
            }
@@ -612,70 +633,94 @@ public class FolderIcon extends FrameLayout implements FolderListener {
            invalidate();
        }

        public void drawBackground(Canvas canvas, Paint paint) {
            canvas.save();
            canvas.translate(getOffsetX(), getOffsetY());

            paint.reset();
            paint.setStyle(Paint.Style.FILL);
            paint.setXfermode(null);
            paint.setAntiAlias(true);

        public void drawBackground(Canvas canvas) {
            mPaint.setStyle(Paint.Style.FILL);
            int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
            paint.setColor(Color.argb(alpha, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY));

            float radius = getScaledRadius();
            mPaint.setColor(Color.argb(alpha, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY));

            canvas.drawCircle(radius, radius, radius, paint);
            canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
            drawCircle(canvas, 0 /* deltaRadius */);

            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(Color.TRANSPARENT);
            paint.setShadowLayer(mStrokeWidth, 0, mStrokeWidth, Color.argb(SHADOW_OPACITY, 0, 0, 0));
            canvas.drawCircle(radius, radius, radius, paint);
            // Draw shadow.
            if (mShadowShader == null) {
                return;
            }
            float radius = getScaledRadius();
            float shadowRadius = radius + mStrokeWidth;
            mPaint.setColor(Color.BLACK);
            int offsetX = getOffsetX();
            int offsetY = getOffsetY();
            final int saveCount;
            if (canvas.isHardwareAccelerated()) {
                saveCount = canvas.saveLayer(offsetX - mStrokeWidth, offsetY,
                        offsetX + radius + shadowRadius, offsetY + shadowRadius + shadowRadius,
                        null, Canvas.CLIP_TO_LAYER_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);

            canvas.restore();
            } else {
                saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
                clipCanvasSoftware(canvas, Region.Op.DIFFERENCE);
            }

        public void drawBackgroundStroke(Canvas canvas, Paint paint) {
            canvas.save();
            canvas.translate(getOffsetX(), getOffsetY());
            mShaderMatrix.setScale(shadowRadius, shadowRadius);
            mShaderMatrix.postTranslate(radius + offsetX, shadowRadius + offsetY);
            mShadowShader.setLocalMatrix(mShaderMatrix);
            mPaint.setShader(mShadowShader);
            canvas.drawPaint(mPaint);
            mPaint.setShader(null);

            paint.reset();
            paint.setAntiAlias(true);
            paint.setColor(Color.argb(255, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY));
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(mStrokeWidth);
            if (canvas.isHardwareAccelerated()) {
                mPaint.setXfermode(mShadowPorterDuffXfermode);
                canvas.drawCircle(radius + offsetX, radius + offsetY, radius, mPaint);
                mPaint.setXfermode(null);
            }

            float radius = getScaledRadius();
            canvas.drawCircle(radius, radius, radius - 1, paint);
            canvas.restoreToCount(saveCount);
        }

            canvas.restore();
        public void drawBackgroundStroke(Canvas canvas) {
            mPaint.setColor(Color.argb(255, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY));
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(mStrokeWidth);
            drawCircle(canvas, 1 /* deltaRadius */);
        }

        public void drawLeaveBehind(Canvas canvas, Paint paint) {
        public void drawLeaveBehind(Canvas canvas) {
            float originalScale = mScale;
            mScale = 0.5f;

            canvas.save();
            canvas.translate(getOffsetX(), getOffsetY());
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(Color.argb(160, 245, 245, 245));
            drawCircle(canvas, 0 /* deltaRadius */);

            paint.reset();
            paint.setAntiAlias(true);
            paint.setColor(Color.argb(160, 245, 245, 245));
            mScale = originalScale;
        }

        private void drawCircle(Canvas canvas,float deltaRadius) {
            float radius = getScaledRadius();
            canvas.drawCircle(radius, radius, radius, paint);
            canvas.drawCircle(radius + getOffsetX(), radius + getOffsetY(),
                    radius - deltaRadius, mPaint);
        }

            canvas.restore();
            mScale = originalScale;
        // It is the callers responsibility to save and restore the canvas layers.
        private void clipCanvasSoftware(Canvas canvas, Region.Op op) {
            mPath.reset();
            float r = getScaledRadius();
            mPath.addCircle(r + getOffsetX(), r + getOffsetY(), r, Path.Direction.CW);
            canvas.clipPath(mPath, op);
        }

        // It is the callers responsibility to save and restore the canvas.
        private void clipCanvas(Canvas canvas) {
            canvas.translate(getOffsetX(), getOffsetY());
            canvas.clipPath(mClipPath);
            canvas.translate(-getOffsetX(), -getOffsetY());
        // It is the callers responsibility to save and restore the canvas layers.
        private void clipCanvasHardware(Canvas canvas) {
            mPaint.setColor(Color.BLACK);
            mPaint.setXfermode(mClipPorterDuffXfermode);

            float radius = getScaledRadius();
            mShaderMatrix.setScale(radius, radius);
            mShaderMatrix.postTranslate(radius + getOffsetX(), radius + getOffsetY());
            mClipShader.setLocalMatrix(mShaderMatrix);
            mPaint.setShader(mClipShader);
            canvas.drawPaint(mPaint);
            mPaint.setXfermode(null);
            mPaint.setShader(null);
        }

        private void delegateDrawing(CellLayout delegate, int cellX, int cellY) {
@@ -795,17 +840,22 @@ public class FolderIcon extends FrameLayout implements FolderListener {
        }

        if (!mBackground.drawingDelegated()) {
            mBackground.drawBackground(canvas, mBgPaint);
            mBackground.drawBackground(canvas);
        }

        if (mFolder == null) return;
        if (mFolder.getItemCount() == 0 && !mAnimating) return;

        canvas.save();

        final int saveCount;

        if (canvas.isHardwareAccelerated()) {
            saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,
                    Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
        } else {
            saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
            if (mPreviewLayoutRule.clipToBackground()) {
            mBackground.clipCanvas(canvas);
                mBackground.clipCanvasSoftware(canvas, Region.Op.INTERSECT);
            }
        }

        // The items are drawn in coordinates relative to the preview offset
@@ -818,18 +868,24 @@ public class FolderIcon extends FrameLayout implements FolderListener {
                drawPreviewItem(canvas, p);
            }
        }
        canvas.restore();
        canvas.translate(-mBackground.basePreviewOffsetX, -mBackground.basePreviewOffsetY);

        if (mPreviewLayoutRule.clipToBackground() && canvas.isHardwareAccelerated()) {
            mBackground.clipCanvasHardware(canvas);
        }
        canvas.restoreToCount(saveCount);

        if (mPreviewLayoutRule.clipToBackground() && !mBackground.drawingDelegated()) {
            mBackground.drawBackgroundStroke(canvas, mBgPaint);
            mBackground.drawBackgroundStroke(canvas);
        }

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