Changing the FolderIcon shape based on AdpativeIcon
> Creating an abstract interface to represent a folderIcon shape
> Defined few common folder shapes
> Picking the folder shape closest to the AdaptiveIcon shape
Bug: 111433118
Change-Id: Ib35eddbdd6692767aa9dbe6aae1a379a68cc456a
diff --git a/src/com/android/launcher3/MainProcessInitializer.java b/src/com/android/launcher3/MainProcessInitializer.java
index a18dfde..a253893 100644
--- a/src/com/android/launcher3/MainProcessInitializer.java
+++ b/src/com/android/launcher3/MainProcessInitializer.java
@@ -19,6 +19,7 @@
import android.content.Context;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.folder.FolderShape;
import com.android.launcher3.graphics.IconShapeOverride;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -39,5 +40,6 @@
FeatureFlags.initialize(context);
IconShapeOverride.apply(context);
SessionCommitReceiver.applyDefaultUserPrefs(context);
+ FolderShape.init();
}
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 11e601c..3f7d68d 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -127,8 +127,8 @@
private static final int DEFAULT_PAGE = 0;
- private static final boolean MAP_NO_RECURSE = false;
- private static final boolean MAP_RECURSE = true;
+ public static final boolean MAP_NO_RECURSE = false;
+ public static final boolean MAP_RECURSE = true;
// The screen id used for the empty screen always present to the right.
public static final int EXTRA_EMPTY_SCREEN_ID = -201;
@@ -3121,7 +3121,7 @@
* @param recurse true: iterate over folder children. false: op get the folders themselves.
* @param op the operator to map over the shortcuts
*/
- void mapOverItems(boolean recurse, ItemOperator op) {
+ public void mapOverItems(boolean recurse, ItemOperator op) {
ArrayList<ShortcutAndWidgetContainer> containers = getAllShortcutAndWidgetContainers();
final int containerCount = containers.size();
for (int containerIdx = 0; containerIdx < containerCount; containerIdx++) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index c4d1058..94c8d45 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -26,6 +26,8 @@
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Path;
import android.graphics.Rect;
import android.text.InputType;
import android.text.Selection;
@@ -151,6 +153,8 @@
// Cell ranks used for drag and drop
@Thunk int mTargetRank, mPrevTargetRank, mEmptyCellRank;
+ private Path mClipPath;
+
@ViewDebug.ExportedProperty(category = "launcher",
mapping = {
@ViewDebug.IntToString(from = STATE_NONE, to = "STATE_NONE"),
@@ -1476,4 +1480,25 @@
sHintText = res.getString(R.string.folder_hint_text);
}
}
+
+ /**
+ * Alternative to using {@link #getClipToOutline()} as it only works with derivatives of
+ * rounded rect.
+ */
+ public void setClipPath(Path clipPath) {
+ mClipPath = clipPath;
+ invalidate();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mClipPath != null) {
+ int count = canvas.save();
+ canvas.clipPath(mClipPath);
+ super.draw(canvas);
+ canvas.restoreToCount(count);
+ } else {
+ super.draw(canvas);
+ }
+ }
}
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 1277a20..fa890b9 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.BubbleTextView.TEXT_ALPHA_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
+import static com.android.launcher3.folder.FolderShape.getShape;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -40,7 +41,6 @@
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PropertyResetListener;
-import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.util.Themes;
@@ -166,7 +166,6 @@
Math.round((totalOffsetX + initialSize) / initialScale),
Math.round((paddingOffsetY + initialSize) / initialScale));
Rect endRect = new Rect(0, 0, lp.width, lp.height);
- float initialRadius = initialSize / initialScale / 2f;
float finalRadius = Utilities.pxFromDp(2, mContext.getResources().getDisplayMetrics());
// Create the animators.
@@ -189,14 +188,8 @@
play(a, getAnimator(mFolder, SCALE_PROPERTY, initialScale, finalScale));
play(a, getAnimator(mFolderBackground, "color", initialColor, finalColor));
play(a, mFolderIcon.mFolderName.createTextAlphaAnimator(!mIsOpening));
- RoundedRectRevealOutlineProvider outlineProvider = new RoundedRectRevealOutlineProvider(
- initialRadius, finalRadius, startRect, endRect) {
- @Override
- public boolean shouldRemoveElevationDuringAnimation() {
- return true;
- }
- };
- play(a, outlineProvider.createRevealAnimator(mFolder, !mIsOpening));
+ play(a, getShape().createRevealAnimator(
+ mFolder, startRect, endRect, finalRadius, !mIsOpening));
// Animate the elevation midway so that the shadow is not noticeable in the background.
int midDuration = mDuration / 2;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index d09f036..429d44f 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -75,6 +75,7 @@
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
public class FolderIcon extends FrameLayout implements FolderListener {
+
@Thunk Launcher mLauncher;
@Thunk Folder mFolder;
private FolderInfo mInfo;
@@ -477,20 +478,9 @@
if (mFolder == null) return;
if (mFolder.getItemCount() == 0 && !mAnimating) return;
- final int saveCount;
-
- if (canvas.isHardwareAccelerated()) {
- saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null);
- } else {
- saveCount = canvas.save();
- canvas.clipPath(mBackground.getClipPath());
- }
-
+ final int saveCount = canvas.save();
+ canvas.clipPath(mBackground.getClipPath());
mPreviewItemManager.draw(canvas);
-
- if (canvas.isHardwareAccelerated()) {
- mBackground.clipCanvasHardware(canvas);
- }
canvas.restoreToCount(saveCount);
if (!mBackground.drawingDelegated()) {
diff --git a/src/com/android/launcher3/folder/FolderShape.java b/src/com/android/launcher3/folder/FolderShape.java
new file mode 100644
index 0000000..ae279cb
--- /dev/null
+++ b/src/com/android/launcher3/folder/FolderShape.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.folder;
+
+import static com.android.launcher3.Workspace.MAP_NO_RECURSE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.FloatArrayEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.Region.Op;
+import android.graphics.RegionIterator;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
+import android.view.ViewOutlineProvider;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+
+/**
+ * Abstract representation of the shape of a folder icon
+ */
+public abstract class FolderShape {
+
+ private static FolderShape sInstance = new Circle();
+
+ public static FolderShape getShape() {
+ return sInstance;
+ }
+
+ private static FolderShape[] getAllShapes() {
+ return new FolderShape[] {
+ new Circle(),
+ new RoundedSquare(8f / 50), // Ratios based on path defined in config_icon_mask
+ new RoundedSquare(30f / 50),
+ new Square(),
+ new TearDrop(),
+ new Squircle()};
+ }
+
+ public abstract void drawShape(Canvas canvas, float offsetX, float offsetY, float radius,
+ Paint paint);
+
+ public abstract void addShape(Path path, float offsetX, float offsetY, float radius);
+
+ public abstract Animator createRevealAnimator(Folder target, Rect startRect, Rect endRect,
+ float endRadius, boolean isReversed);
+
+ /**
+ * Abstract shape where the reveal animation is a derivative of a round rect animation
+ */
+ private static abstract class SimpleRectShape extends FolderShape {
+
+ @Override
+ public final Animator createRevealAnimator(Folder target, Rect startRect, Rect endRect,
+ float endRadius, boolean isReversed) {
+ return new RoundedRectRevealOutlineProvider(
+ getStartRadius(startRect), endRadius, startRect, endRect) {
+ @Override
+ public boolean shouldRemoveElevationDuringAnimation() {
+ return true;
+ }
+ }.createRevealAnimator(target, isReversed);
+ }
+
+ protected abstract float getStartRadius(Rect startRect);
+ }
+
+ /**
+ * Abstract shape which draws using {@link Path}
+ */
+ private static abstract class PathShape extends FolderShape {
+
+ private final Path mTmpPath = new Path();
+
+ @Override
+ public final void drawShape(Canvas canvas, float offsetX, float offsetY, float radius,
+ Paint paint) {
+ mTmpPath.reset();
+ addShape(mTmpPath, offsetX, offsetY, radius);
+ canvas.drawPath(mTmpPath, paint);
+ }
+
+ protected abstract AnimatorUpdateListener newUpdateListener(
+ Rect startRect, Rect endRect, float endRadius, Path outPath);
+
+ @Override
+ public final Animator createRevealAnimator(Folder target, Rect startRect, Rect endRect,
+ float endRadius, boolean isReversed) {
+ Path path = new Path();
+ AnimatorUpdateListener listener =
+ newUpdateListener(startRect, endRect, endRadius, path);
+
+ ValueAnimator va =
+ isReversed ? ValueAnimator.ofFloat(1f, 0f) : ValueAnimator.ofFloat(0f, 1f);
+ va.addListener(new AnimatorListenerAdapter() {
+ private ViewOutlineProvider mOldOutlineProvider;
+
+ public void onAnimationStart(Animator animation) {
+ mOldOutlineProvider = target.getOutlineProvider();
+ target.setOutlineProvider(null);
+
+ target.setTranslationZ(-target.getElevation());
+ }
+
+ public void onAnimationEnd(Animator animation) {
+ target.setTranslationZ(0);
+ target.setClipPath(null);
+ target.setOutlineProvider(mOldOutlineProvider);
+ }
+ });
+
+ va.addUpdateListener((anim) -> {
+ path.reset();
+ listener.onAnimationUpdate(anim);
+ target.setClipPath(path);
+ });
+
+ return va;
+ }
+ }
+
+ public static final class Circle extends SimpleRectShape {
+
+ @Override
+ public void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint p) {
+ canvas.drawCircle(radius + offsetX, radius + offsetY, radius, p);
+ }
+
+ @Override
+ public void addShape(Path path, float offsetX, float offsetY, float radius) {
+ path.addCircle(radius + offsetX, radius + offsetY, radius, Path.Direction.CW);
+ }
+
+ @Override
+ protected float getStartRadius(Rect startRect) {
+ return startRect.width() / 2f;
+ }
+ }
+
+ public static class Square extends SimpleRectShape {
+
+ @Override
+ public void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint p) {
+ float cx = radius + offsetX;
+ float cy = radius + offsetY;
+ canvas.drawRect(cx - radius, cy - radius, cx + radius, cy + radius, p);
+ }
+
+ @Override
+ public void addShape(Path path, float offsetX, float offsetY, float radius) {
+ float cx = radius + offsetX;
+ float cy = radius + offsetY;
+ path.addRect(cx - radius, cy - radius, cx + radius, cy + radius, Path.Direction.CW);
+ }
+
+ @Override
+ protected float getStartRadius(Rect startRect) {
+ return 0;
+ }
+ }
+
+ public static class RoundedSquare extends SimpleRectShape {
+
+ /**
+ * Ratio of corner radius to half size. Based on the
+ */
+ private final float mRadiusFactor;
+
+ public RoundedSquare(float radiusFactor) {
+ mRadiusFactor = radiusFactor;
+ }
+
+ @Override
+ public void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint p) {
+ float cx = radius + offsetX;
+ float cy = radius + offsetY;
+ float cr = radius * mRadiusFactor;
+ canvas.drawRoundRect(cx - radius, cy - radius, cx + radius, cy + radius, cr, cr, p);
+ }
+
+ @Override
+ public void addShape(Path path, float offsetX, float offsetY, float radius) {
+ float cx = radius + offsetX;
+ float cy = radius + offsetY;
+ float cr = radius * mRadiusFactor;
+ path.addRoundRect(cx - radius, cy - radius, cx + radius, cy + radius, cr, cr,
+ Path.Direction.CW);
+ }
+
+ @Override
+ protected float getStartRadius(Rect startRect) {
+ return (startRect.width() / 2f) * mRadiusFactor;
+ }
+ }
+
+ public static class TearDrop extends PathShape {
+
+ /**
+ * Radio of short radius to large radius, based on the shape options defined in the config.
+ */
+ private static final float RADIUS_RATIO = 15f / 50;
+
+ private final float[] mTempRadii = new float[8];
+
+ @Override
+ public void addShape(Path p, float offsetX, float offsetY, float r1) {
+ float r2 = r1 * RADIUS_RATIO;
+ float cx = r1 + offsetX;
+ float cy = r1 + offsetY;
+
+ p.addRoundRect(cx - r1, cy - r1, cx + r1, cy + r1, getRadiiArray(r1, r2),
+ Path.Direction.CW);
+ }
+
+ private float[] getRadiiArray(float r1, float r2) {
+ mTempRadii[0] = mTempRadii [1] = mTempRadii[2] = mTempRadii[3] =
+ mTempRadii[6] = mTempRadii[7] = r1;
+ mTempRadii[4] = mTempRadii[5] = r2;
+ return mTempRadii;
+ }
+
+ @Override
+ protected AnimatorUpdateListener newUpdateListener(Rect startRect, Rect endRect,
+ float endRadius, Path outPath) {
+ float r1 = startRect.width() / 2f;
+ float r2 = r1 * RADIUS_RATIO;
+
+ float[] startValues = new float[] {
+ startRect.left, startRect.top, startRect.right, startRect.bottom, r1, r2};
+ float[] endValues = new float[] {
+ endRect.left, endRect.top, endRect.right, endRect.bottom, endRadius, endRadius};
+
+ FloatArrayEvaluator evaluator = new FloatArrayEvaluator(new float[6]);
+
+ return (anim) -> {
+ float progress = (Float) anim.getAnimatedValue();
+ float[] values = evaluator.evaluate(progress, startValues, endValues);
+ outPath.addRoundRect(
+ values[0], values[1], values[2], values[3],
+ getRadiiArray(values[4], values[5]), Path.Direction.CW);
+ };
+ }
+ }
+
+ public static class Squircle extends PathShape {
+
+ /**
+ * Radio of radius to circle radius, based on the shape options defined in the config.
+ */
+ private static final float RADIUS_RATIO = 10f / 50;
+
+ @Override
+ public void addShape(Path p, float offsetX, float offsetY, float r) {
+ float cx = r + offsetX;
+ float cy = r + offsetY;
+ float control = r - r * RADIUS_RATIO;
+
+ p.moveTo(cx, cy - r);
+ addLeftCurve(cx, cy, r, control, p);
+ addRightCurve(cx, cy, r, control, p);
+ addLeftCurve(cx, cy, -r, -control, p);
+ addRightCurve(cx, cy, -r, -control, p);
+ p.close();
+ }
+
+ private void addLeftCurve(float cx, float cy, float r, float control, Path path) {
+ path.cubicTo(
+ cx - control, cy - r,
+ cx - r, cy - control,
+ cx - r, cy);
+ }
+
+ private void addRightCurve(float cx, float cy, float r, float control, Path path) {
+ path.cubicTo(
+ cx - r, cy + control,
+ cx - control, cy + r,
+ cx, cy + r);
+ }
+
+ @Override
+ protected AnimatorUpdateListener newUpdateListener(Rect startRect, Rect endRect,
+ float endR, Path outPath) {
+
+ float startCX = startRect.exactCenterX();
+ float startCY = startRect.exactCenterY();
+ float startR = startRect.width() / 2f;
+ float startControl = startR - startR * RADIUS_RATIO;
+ float startHShift = 0;
+ float startVShift = 0;
+
+ float endCX = endRect.exactCenterX();
+ float endCY = endRect.exactCenterY();
+ // Approximate corner circle using bezier curves
+ // http://spencermortensen.com/articles/bezier-circle/
+ float endControl = endR * 0.551915024494f;
+ float endHShift = endRect.width() / 2f - endR;
+ float endVShift = endRect.height() / 2f - endR;
+
+ return (anim) -> {
+ float progress = (Float) anim.getAnimatedValue();
+
+ float cx = (1 - progress) * startCX + progress * endCX;
+ float cy = (1 - progress) * startCY + progress * endCY;
+ float r = (1 - progress) * startR + progress * endR;
+ float control = (1 - progress) * startControl + progress * endControl;
+ float hShift = (1 - progress) * startHShift + progress * endHShift;
+ float vShift = (1 - progress) * startVShift + progress * endVShift;
+
+ outPath.moveTo(cx, cy - vShift - r);
+ outPath.rLineTo(-hShift, 0);
+
+ addLeftCurve(cx - hShift, cy - vShift, r, control, outPath);
+ outPath.rLineTo(0, vShift + vShift);
+
+ addRightCurve(cx - hShift, cy + vShift, r, control, outPath);
+ outPath.rLineTo(hShift + hShift, 0);
+
+ addLeftCurve(cx + hShift, cy + vShift, -r, -control, outPath);
+ outPath.rLineTo(0, -vShift - vShift);
+
+ addRightCurve(cx + hShift, cy - vShift, -r, -control, outPath);
+ outPath.close();
+ };
+ }
+ }
+
+ /**
+ * Initializes the shape which is closest to closest to the {@link AdaptiveIconDrawable}
+ */
+ public static void init() {
+ if (!Utilities.ATLEAST_OREO) {
+ return;
+ }
+ new MainThreadExecutor().execute(FolderShape::pickShapeInBackground);
+ }
+
+ @TargetApi(Build.VERSION_CODES.O)
+ protected static void pickShapeInBackground() {
+ // Pick any large size
+ int size = 200;
+
+ Region full = new Region(0, 0, size, size);
+ Region iconR = new Region();
+ AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
+ new ColorDrawable(Color.BLACK), new ColorDrawable(Color.BLACK));
+ drawable.setBounds(0, 0, size, size);
+ iconR.setPath(drawable.getIconMask(), full);
+
+ Path shapePath = new Path();
+ Region shapeR = new Region();
+ Rect tempRect = new Rect();
+
+ // Find the shape with minimum area of divergent region.
+ int minArea = Integer.MAX_VALUE;
+ FolderShape closestShape = null;
+ for (FolderShape shape : getAllShapes()) {
+ shapePath.reset();
+ shape.addShape(shapePath, 0, 0, size / 2f);
+ shapeR.setPath(shapePath, full);
+ shapeR.op(iconR, Op.XOR);
+
+ RegionIterator itr = new RegionIterator(shapeR);
+ int area = 0;
+
+ while (itr.next(tempRect)) {
+ area += tempRect.width() * tempRect.height();
+ }
+ if (area < minArea) {
+ minArea = area;
+ closestShape = shape;
+ }
+ }
+
+ if (closestShape != null) {
+ FolderShape shape = closestShape;
+ new MainThreadExecutor().execute(() -> updateFolderShape(shape));
+ }
+ }
+
+ private static void updateFolderShape(FolderShape shape) {
+ sInstance = shape;
+ LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+ if (app == null) {
+ return;
+ }
+ Launcher launcher = (Launcher) app.getModel().getCallback();
+ if (launcher != null) {
+ launcher.getWorkspace().mapOverItems(MAP_NO_RECURSE, (i, v) -> {
+ if (v instanceof FolderIcon) {
+ v.invalidate();
+ }
+ return false;
+ });
+ }
+ }
+}
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index ceb1a8c..8443953 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -16,6 +16,8 @@
package com.android.launcher3.folder;
+import static com.android.launcher3.folder.FolderShape.getShape;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -49,16 +51,6 @@
private static final int CONSUMPTION_ANIMATION_DURATION = 100;
- 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;
@@ -208,8 +200,7 @@
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(getBgColor());
- drawCircle(canvas, 0 /* deltaRadius */);
-
+ getShape().drawShape(canvas, getOffsetX(), getOffsetY(), getScaledRadius(), mPaint);
drawShadow(canvas);
}
@@ -244,7 +235,7 @@
mPaint.setShader(null);
if (canvas.isHardwareAccelerated()) {
mPaint.setXfermode(mShadowPorterDuffXfermode);
- canvas.drawCircle(radius + offsetX, radius + offsetY, radius, mPaint);
+ getShape().drawShape(canvas, offsetX, offsetY, radius, mPaint);
mPaint.setXfermode(null);
}
@@ -287,7 +278,10 @@
mPaint.setColor(ColorUtils.setAlphaComponent(mBgColor, mStrokeAlpha));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth);
- drawCircle(canvas, 1 /* deltaRadius */);
+
+ float inset = 1f;
+ getShape().drawShape(canvas,
+ getOffsetX() + inset, getOffsetY() + inset, getScaledRadius() - inset, mPaint);
}
public void drawLeaveBehind(Canvas canvas) {
@@ -296,40 +290,17 @@
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.argb(160, 245, 245, 245));
- drawCircle(canvas, 0 /* deltaRadius */);
+ getShape().drawShape(canvas, getOffsetX(), getOffsetY(), getScaledRadius(), mPaint);
mScale = originalScale;
}
- private void drawCircle(Canvas canvas,float deltaRadius) {
- float radius = getScaledRadius();
- canvas.drawCircle(radius + getOffsetX(), radius + getOffsetY(),
- radius - deltaRadius, mPaint);
- }
-
public Path getClipPath() {
mPath.reset();
- float r = getScaledRadius();
- mPath.addCircle(r + getOffsetX(), r + getOffsetY(), r, Path.Direction.CW);
+ getShape().addShape(mPath, getOffsetX(), getOffsetY(), getScaledRadius());
return mPath;
}
- // It is the callers responsibility to save and restore the canvas layers.
- void clipCanvasHardware(Canvas canvas) {
- mPaint.setColor(Color.BLACK);
- mPaint.setStyle(Paint.Style.FILL);
- 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) {
if (mDrawingDelegate != delegate) {
delegate.addFolderBackground(this);