Loading src/com/android/launcher3/CellLayout.java +4 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } Loading @@ -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(); } } Loading @@ -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(); } } Loading src/com/android/launcher3/folder/FolderIcon.java +128 −72 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -125,8 +129,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(); Loading Loading @@ -179,11 +181,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); Loading Loading @@ -493,7 +490,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; Loading @@ -520,10 +517,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; Loading @@ -546,7 +562,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; Loading @@ -562,7 +578,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(); } Loading Loading @@ -592,10 +617,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(); } Loading @@ -610,70 +631,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) { Loading Loading @@ -793,17 +838,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 Loading @@ -816,18 +866,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); } Loading Loading
src/com/android/launcher3/CellLayout.java +4 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } Loading @@ -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(); } } Loading @@ -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(); } } Loading
src/com/android/launcher3/folder/FolderIcon.java +128 −72 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -125,8 +129,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(); Loading Loading @@ -179,11 +181,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); Loading Loading @@ -493,7 +490,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; Loading @@ -520,10 +517,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; Loading @@ -546,7 +562,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; Loading @@ -562,7 +578,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(); } Loading Loading @@ -592,10 +617,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(); } Loading @@ -610,70 +631,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) { Loading Loading @@ -793,17 +838,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 Loading @@ -816,18 +866,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); } Loading