Adding utility method to get adaptive icon scale
Change-Id: I5ff190c3b794bb13309375782ccd420e85b59091
This commit is contained in:
@@ -78,7 +78,7 @@ public class BaseIconFactory implements AutoCloseable {
|
||||
|
||||
public IconNormalizer getNormalizer() {
|
||||
if (mNormalizer == null) {
|
||||
mNormalizer = new IconNormalizer(mContext, mIconBitmapSize);
|
||||
mNormalizer = new IconNormalizer(mIconBitmapSize);
|
||||
}
|
||||
return mNormalizer;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
package com.android.launcher3.icons;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.RegionIterator;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -60,4 +63,14 @@ public class GraphicsUtils {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getArea(Region r) {
|
||||
RegionIterator itr = new RegionIterator(r);
|
||||
int area = 0;
|
||||
Rect tempRect = new Rect();
|
||||
while (itr.next(tempRect)) {
|
||||
area += tempRect.width() * tempRect.height();
|
||||
}
|
||||
return area;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,18 @@
|
||||
|
||||
package com.android.launcher3.icons;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@@ -57,7 +61,7 @@ public class IconNormalizer {
|
||||
private final Canvas mCanvas;
|
||||
private final byte[] mPixels;
|
||||
|
||||
private final Rect mAdaptiveIconBounds;
|
||||
private final RectF mAdaptiveIconBounds;
|
||||
private float mAdaptiveIconScale;
|
||||
|
||||
// for each y, stores the position of the leftmost x and the rightmost x
|
||||
@@ -66,7 +70,7 @@ public class IconNormalizer {
|
||||
private final Rect mBounds;
|
||||
|
||||
/** package private **/
|
||||
IconNormalizer(Context context, int iconBitmapSize) {
|
||||
IconNormalizer(int iconBitmapSize) {
|
||||
// Use twice the icon size as maximum size to avoid scaling down twice.
|
||||
mMaxSize = iconBitmapSize * 2;
|
||||
mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
|
||||
@@ -75,11 +79,53 @@ public class IconNormalizer {
|
||||
mLeftBorder = new float[mMaxSize];
|
||||
mRightBorder = new float[mMaxSize];
|
||||
mBounds = new Rect();
|
||||
mAdaptiveIconBounds = new Rect();
|
||||
mAdaptiveIconBounds = new RectF();
|
||||
|
||||
mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
private static float getScale(float hullArea, float boundingArea, float fullArea) {
|
||||
float hullByRect = hullArea / boundingArea;
|
||||
float scaleRequired;
|
||||
if (hullByRect < CIRCLE_AREA_BY_RECT) {
|
||||
scaleRequired = MAX_CIRCLE_AREA_FACTOR;
|
||||
} else {
|
||||
scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect);
|
||||
}
|
||||
|
||||
float areaScale = hullArea / fullArea;
|
||||
// Use sqrt of the final ratio as the images is scaled across both width and height.
|
||||
return areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param d Should be AdaptiveIconDrawable
|
||||
* @param size Canvas size to use
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public static float normalizeAdaptiveIcon(Drawable d, int size, @Nullable RectF outBounds) {
|
||||
Rect tmpBounds = new Rect(d.getBounds());
|
||||
d.setBounds(0, 0, size, size);
|
||||
|
||||
Path path = ((AdaptiveIconDrawable) d).getIconMask();
|
||||
Region region = new Region();
|
||||
region.setPath(path, new Region(0, 0, size, size));
|
||||
|
||||
Rect hullBounds = region.getBounds();
|
||||
int hullArea = GraphicsUtils.getArea(region);
|
||||
|
||||
if (outBounds != null) {
|
||||
float sizeF = size;
|
||||
outBounds.set(
|
||||
hullBounds.left / sizeF,
|
||||
hullBounds.top / sizeF,
|
||||
1 - (hullBounds.right / sizeF),
|
||||
1 - (hullBounds.bottom / sizeF));
|
||||
}
|
||||
d.setBounds(tmpBounds);
|
||||
return getScale(hullArea, hullArea, size * size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount by which the {@param d} should be scaled (in both dimensions) so that it
|
||||
* matches the design guidelines for a launcher icon.
|
||||
@@ -96,12 +142,13 @@ public class IconNormalizer {
|
||||
*/
|
||||
public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds) {
|
||||
if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) {
|
||||
if (mAdaptiveIconScale != SCALE_NOT_INITIALIZED) {
|
||||
if (outBounds != null) {
|
||||
outBounds.set(mAdaptiveIconBounds);
|
||||
}
|
||||
return mAdaptiveIconScale;
|
||||
if (mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
|
||||
mAdaptiveIconScale = normalizeAdaptiveIcon(d, mMaxSize, mAdaptiveIconBounds);
|
||||
}
|
||||
if (outBounds != null) {
|
||||
outBounds.set(mAdaptiveIconBounds);
|
||||
}
|
||||
return mAdaptiveIconScale;
|
||||
}
|
||||
int width = d.getIntrinsicWidth();
|
||||
int height = d.getIntrinsicHeight();
|
||||
@@ -184,16 +231,6 @@ public class IconNormalizer {
|
||||
area += mRightBorder[y] - mLeftBorder[y] + 1;
|
||||
}
|
||||
|
||||
// Area of the rectangle required to fit the convex hull
|
||||
float rectArea = (bottomY + 1 - topY) * (rightX + 1 - leftX);
|
||||
float hullByRect = area / rectArea;
|
||||
|
||||
float scaleRequired;
|
||||
if (hullByRect < CIRCLE_AREA_BY_RECT) {
|
||||
scaleRequired = MAX_CIRCLE_AREA_FACTOR;
|
||||
} else {
|
||||
scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect);
|
||||
}
|
||||
mBounds.left = leftX;
|
||||
mBounds.right = rightX;
|
||||
|
||||
@@ -205,15 +242,10 @@ public class IconNormalizer {
|
||||
1 - ((float) mBounds.right) / width,
|
||||
1 - ((float) mBounds.bottom) / height);
|
||||
}
|
||||
float areaScale = area / (width * height);
|
||||
// Use sqrt of the final ratio as the images is scaled across both width and height.
|
||||
float scale = areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
|
||||
if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable &&
|
||||
mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
|
||||
mAdaptiveIconScale = scale;
|
||||
mAdaptiveIconBounds.set(mBounds);
|
||||
}
|
||||
return scale;
|
||||
|
||||
// Area of the rectangle required to fit the convex hull
|
||||
float rectArea = (bottomY + 1 - topY) * (rightX + 1 - leftX);
|
||||
return getScale(area, rectArea, width * height);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,7 +42,7 @@ import android.util.Xml;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.launcher3.folder.FolderShape;
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
import com.android.launcher3.util.ConfigMonitor;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
@@ -304,7 +304,7 @@ public class InvariantDeviceProfile {
|
||||
changeFlags |= CHANGE_FLAG_ICON_PARAMS;
|
||||
}
|
||||
if (!iconShapePath.equals(oldProfile.iconShapePath)) {
|
||||
FolderShape.init(context);
|
||||
IconShape.init(context);
|
||||
}
|
||||
|
||||
apply(context, changeFlags);
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.android.launcher3;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.folder.FolderShape;
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
|
||||
@@ -38,6 +38,6 @@ public class MainProcessInitializer implements ResourceBasedOverride {
|
||||
FileLog.setDir(context.getApplicationContext().getFilesDir());
|
||||
FeatureFlags.initialize(context);
|
||||
SessionCommitReceiver.applyDefaultUserPrefs(context);
|
||||
FolderShape.init(context);
|
||||
IconShape.init(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.android.launcher3.folder;
|
||||
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 static com.android.launcher3.graphics.IconShape.getShape;
|
||||
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
|
||||
|
||||
import android.animation.Animator;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.launcher3.folder;
|
||||
|
||||
import static com.android.launcher3.folder.FolderShape.getShape;
|
||||
import static com.android.launcher3.graphics.IconShape.getShape;
|
||||
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -311,7 +311,7 @@ public class PreviewBackground {
|
||||
|
||||
public Path getClipPath() {
|
||||
mPath.reset();
|
||||
getShape().addShape(mPath, getOffsetX(), getOffsetY(), getScaledRadius());
|
||||
getShape().addToPath(mPath, getOffsetX(), getOffsetY(), getScaledRadius());
|
||||
return mPath;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
|
||||
package com.android.launcher3.graphics;
|
||||
|
||||
import static com.android.launcher3.graphics.IconShape.getShapePath;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Process;
|
||||
@@ -34,7 +34,6 @@ import android.util.ArrayMap;
|
||||
import com.android.launcher3.FastBitmapDrawable;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
@@ -47,16 +46,8 @@ import androidx.annotation.UiThread;
|
||||
public class DrawableFactory implements ResourceBasedOverride {
|
||||
|
||||
public static final MainThreadInitializedObject<DrawableFactory> INSTANCE =
|
||||
new MainThreadInitializedObject<>(c -> {
|
||||
DrawableFactory factory = Overrides.getObject(DrawableFactory.class,
|
||||
c.getApplicationContext(), R.string.drawable_factory_class);
|
||||
factory.mContext = c;
|
||||
return factory;
|
||||
});
|
||||
|
||||
|
||||
private Context mContext;
|
||||
private Path mPreloadProgressPath;
|
||||
new MainThreadInitializedObject<>(c -> Overrides.getObject(DrawableFactory.class,
|
||||
c.getApplicationContext(), R.string.drawable_factory_class));
|
||||
|
||||
protected final UserHandle mMyUser = Process.myUserHandle();
|
||||
protected final ArrayMap<UserHandle, Bitmap> mUserBadges = new ArrayMap<>();
|
||||
@@ -66,7 +57,7 @@ public class DrawableFactory implements ResourceBasedOverride {
|
||||
*/
|
||||
public FastBitmapDrawable newIcon(Context context, ItemInfoWithIcon info) {
|
||||
FastBitmapDrawable drawable = info.usingLowResIcon()
|
||||
? new PlaceHolderIconDrawable(info, getPreloadProgressPath(), context)
|
||||
? new PlaceHolderIconDrawable(info, getShapePath(), context)
|
||||
: new FastBitmapDrawable(info);
|
||||
drawable.setIsDisabled(info.isDisabled());
|
||||
return drawable;
|
||||
@@ -74,7 +65,7 @@ public class DrawableFactory implements ResourceBasedOverride {
|
||||
|
||||
public FastBitmapDrawable newIcon(Context context, BitmapInfo info, ActivityInfo target) {
|
||||
return info.isLowRes()
|
||||
? new PlaceHolderIconDrawable(info, getPreloadProgressPath(), context)
|
||||
? new PlaceHolderIconDrawable(info, getShapePath(), context)
|
||||
: new FastBitmapDrawable(info);
|
||||
}
|
||||
|
||||
@@ -82,29 +73,7 @@ public class DrawableFactory implements ResourceBasedOverride {
|
||||
* Returns a FastBitmapDrawable with the icon.
|
||||
*/
|
||||
public PreloadIconDrawable newPendingIcon(Context context, ItemInfoWithIcon info) {
|
||||
return new PreloadIconDrawable(info, getPreloadProgressPath(), context);
|
||||
}
|
||||
|
||||
protected Path getPreloadProgressPath() {
|
||||
if (mPreloadProgressPath != null) {
|
||||
return mPreloadProgressPath;
|
||||
}
|
||||
if (Utilities.ATLEAST_OREO) {
|
||||
// Load the path from Mask Icon
|
||||
AdaptiveIconDrawable icon = (AdaptiveIconDrawable)
|
||||
mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper);
|
||||
icon.setBounds(0, 0,
|
||||
PreloadIconDrawable.PATH_SIZE, PreloadIconDrawable.PATH_SIZE);
|
||||
mPreloadProgressPath = icon.getIconMask();
|
||||
} else {
|
||||
|
||||
// Create a circle static from top center and going clockwise.
|
||||
Path p = new Path();
|
||||
p.moveTo(PreloadIconDrawable.PATH_SIZE / 2, 0);
|
||||
p.addArc(0, 0, PreloadIconDrawable.PATH_SIZE, PreloadIconDrawable.PATH_SIZE, -90, 360);
|
||||
mPreloadProgressPath = p;
|
||||
}
|
||||
return mPreloadProgressPath;
|
||||
return new PreloadIconDrawable(info, getShapePath(), context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+48
-29
@@ -13,7 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.folder;
|
||||
package com.android.launcher3.graphics;
|
||||
|
||||
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -31,7 +33,6 @@ 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;
|
||||
@@ -45,6 +46,8 @@ import android.view.ViewOutlineProvider;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
|
||||
import com.android.launcher3.icons.GraphicsUtils;
|
||||
import com.android.launcher3.icons.IconNormalizer;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.ClipPathView;
|
||||
@@ -59,22 +62,39 @@ import java.util.List;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Abstract representation of the shape of a folder icon
|
||||
* Abstract representation of the shape of an icon shape
|
||||
*/
|
||||
public abstract class FolderShape {
|
||||
public abstract class IconShape {
|
||||
|
||||
private static FolderShape sInstance = new Circle();
|
||||
private static IconShape sInstance = new Circle();
|
||||
private static Path sShapePath;
|
||||
private static float sNormalizationScale = ICON_VISIBLE_AREA_FACTOR;
|
||||
|
||||
public static FolderShape getShape() {
|
||||
public static final int DEFAULT_PATH_SIZE = 100;
|
||||
|
||||
public static IconShape getShape() {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public static Path getShapePath() {
|
||||
if (sShapePath == null) {
|
||||
Path p = new Path();
|
||||
getShape().addToPath(p, 0, 0, DEFAULT_PATH_SIZE * 0.5f);
|
||||
sShapePath = p;
|
||||
}
|
||||
return sShapePath;
|
||||
}
|
||||
|
||||
public static float getNormalizationScale() {
|
||||
return sNormalizationScale;
|
||||
}
|
||||
|
||||
private SparseArray<TypedValue> mAttrs;
|
||||
|
||||
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 void addToPath(Path path, float offsetX, float offsetY, float radius);
|
||||
|
||||
public abstract <T extends View & ClipPathView> Animator createRevealAnimator(T target,
|
||||
Rect startRect, Rect endRect, float endRadius, boolean isReversed);
|
||||
@@ -87,7 +107,7 @@ public abstract class FolderShape {
|
||||
/**
|
||||
* Abstract shape where the reveal animation is a derivative of a round rect animation
|
||||
*/
|
||||
private static abstract class SimpleRectShape extends FolderShape {
|
||||
private static abstract class SimpleRectShape extends IconShape {
|
||||
|
||||
@Override
|
||||
public final <T extends View & ClipPathView> Animator createRevealAnimator(T target,
|
||||
@@ -107,7 +127,7 @@ public abstract class FolderShape {
|
||||
/**
|
||||
* Abstract shape which draws using {@link Path}
|
||||
*/
|
||||
private static abstract class PathShape extends FolderShape {
|
||||
private static abstract class PathShape extends IconShape {
|
||||
|
||||
private final Path mTmpPath = new Path();
|
||||
|
||||
@@ -115,7 +135,7 @@ public abstract class FolderShape {
|
||||
public final void drawShape(Canvas canvas, float offsetX, float offsetY, float radius,
|
||||
Paint paint) {
|
||||
mTmpPath.reset();
|
||||
addShape(mTmpPath, offsetX, offsetY, radius);
|
||||
addToPath(mTmpPath, offsetX, offsetY, radius);
|
||||
canvas.drawPath(mTmpPath, paint);
|
||||
}
|
||||
|
||||
@@ -166,7 +186,7 @@ public abstract class FolderShape {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addShape(Path path, float offsetX, float offsetY, float radius) {
|
||||
public void addToPath(Path path, float offsetX, float offsetY, float radius) {
|
||||
path.addCircle(radius + offsetX, radius + offsetY, radius, Path.Direction.CW);
|
||||
}
|
||||
|
||||
@@ -196,7 +216,7 @@ public abstract class FolderShape {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addShape(Path path, float offsetX, float offsetY, float radius) {
|
||||
public void addToPath(Path path, float offsetX, float offsetY, float radius) {
|
||||
float cx = radius + offsetX;
|
||||
float cy = radius + offsetY;
|
||||
float cr = radius * mRadiusRatio;
|
||||
@@ -223,7 +243,7 @@ public abstract class FolderShape {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addShape(Path p, float offsetX, float offsetY, float r1) {
|
||||
public void addToPath(Path p, float offsetX, float offsetY, float r1) {
|
||||
float r2 = r1 * mRadiusRatio;
|
||||
float cx = r1 + offsetX;
|
||||
float cy = r1 + offsetY;
|
||||
@@ -274,7 +294,7 @@ public abstract class FolderShape {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addShape(Path p, float offsetX, float offsetY, float r) {
|
||||
public void addToPath(Path p, float offsetX, float offsetY, float r) {
|
||||
float cx = r + offsetX;
|
||||
float cy = r + offsetY;
|
||||
float control = r - r * mRadiusRatio;
|
||||
@@ -358,7 +378,7 @@ public abstract class FolderShape {
|
||||
pickBestShape(context);
|
||||
}
|
||||
|
||||
private static FolderShape getShapeDefinition(String type, float radius) {
|
||||
private static IconShape getShapeDefinition(String type, float radius) {
|
||||
switch (type) {
|
||||
case "Circle":
|
||||
return new Circle();
|
||||
@@ -373,8 +393,8 @@ public abstract class FolderShape {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<FolderShape> getAllShapes(Context context) {
|
||||
ArrayList<FolderShape> result = new ArrayList<>();
|
||||
private static List<IconShape> getAllShapes(Context context) {
|
||||
ArrayList<IconShape> result = new ArrayList<>();
|
||||
try (XmlResourceParser parser = context.getResources().getXml(R.xml.folder_shapes)) {
|
||||
|
||||
// Find the root tag
|
||||
@@ -393,7 +413,7 @@ public abstract class FolderShape {
|
||||
if (type == XmlPullParser.START_TAG) {
|
||||
AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, radiusAttr);
|
||||
FolderShape shape = getShapeDefinition(parser.getName(), a.getFloat(0, 1));
|
||||
IconShape shape = getShapeDefinition(parser.getName(), a.getFloat(0, 1));
|
||||
a.recycle();
|
||||
|
||||
shape.mAttrs = Themes.createValueMap(context, attrs, keysToIgnore);
|
||||
@@ -409,7 +429,7 @@ public abstract class FolderShape {
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
protected static void pickBestShape(Context context) {
|
||||
// Pick any large size
|
||||
int size = 200;
|
||||
final int size = 200;
|
||||
|
||||
Region full = new Region(0, 0, size, size);
|
||||
Region iconR = new Region();
|
||||
@@ -420,23 +440,17 @@ public abstract class FolderShape {
|
||||
|
||||
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(context)) {
|
||||
IconShape closestShape = null;
|
||||
for (IconShape shape : getAllShapes(context)) {
|
||||
shapePath.reset();
|
||||
shape.addShape(shapePath, 0, 0, size / 2f);
|
||||
shape.addToPath(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();
|
||||
}
|
||||
int area = GraphicsUtils.getArea(shapeR);
|
||||
if (area < minArea) {
|
||||
minArea = area;
|
||||
closestShape = shape;
|
||||
@@ -446,5 +460,10 @@ public abstract class FolderShape {
|
||||
if (closestShape != null) {
|
||||
sInstance = closestShape;
|
||||
}
|
||||
|
||||
// Initialize shape properties
|
||||
drawable.setBounds(0, 0, DEFAULT_PATH_SIZE, DEFAULT_PATH_SIZE);
|
||||
sShapePath = new Path(drawable.getIconMask());
|
||||
sNormalizationScale = IconNormalizer.normalizeAdaptiveIcon(drawable, size, null);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
package com.android.launcher3.graphics;
|
||||
|
||||
import static com.android.launcher3.graphics.IconShape.DEFAULT_PATH_SIZE;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
@@ -55,8 +57,6 @@ public class PreloadIconDrawable extends FastBitmapDrawable {
|
||||
}
|
||||
};
|
||||
|
||||
public static final int PATH_SIZE = 100;
|
||||
|
||||
private static final float PROGRESS_WIDTH = 7;
|
||||
private static final float PROGRESS_GAP = 2;
|
||||
private static final int MAX_PAINT_ALPHA = 255;
|
||||
@@ -123,14 +123,14 @@ public class PreloadIconDrawable extends FastBitmapDrawable {
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
mTmpMatrix.setScale(
|
||||
(bounds.width() - 2 * PROGRESS_WIDTH - 2 * PROGRESS_GAP) / PATH_SIZE,
|
||||
(bounds.height() - 2 * PROGRESS_WIDTH - 2 * PROGRESS_GAP) / PATH_SIZE);
|
||||
(bounds.width() - 2 * PROGRESS_WIDTH - 2 * PROGRESS_GAP) / DEFAULT_PATH_SIZE,
|
||||
(bounds.height() - 2 * PROGRESS_WIDTH - 2 * PROGRESS_GAP) / DEFAULT_PATH_SIZE);
|
||||
mTmpMatrix.postTranslate(
|
||||
bounds.left + PROGRESS_WIDTH + PROGRESS_GAP,
|
||||
bounds.top + PROGRESS_WIDTH + PROGRESS_GAP);
|
||||
|
||||
mProgressPath.transform(mTmpMatrix, mScaledTrackPath);
|
||||
float scale = bounds.width() / PATH_SIZE;
|
||||
float scale = bounds.width() / DEFAULT_PATH_SIZE;
|
||||
mProgressPaint.setStrokeWidth(PROGRESS_WIDTH * scale);
|
||||
|
||||
mShadowBitmap = getShadowBitmap(bounds.width(), bounds.height(),
|
||||
|
||||
@@ -54,7 +54,7 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.folder.FolderShape;
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
import com.android.launcher3.graphics.ShiftedBitmapDrawable;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
@@ -144,7 +144,7 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
|
||||
mTaskCornerRadius = cornerRadius;
|
||||
if (mIsAdaptiveIcon && shapeRevealProgress >= 0) {
|
||||
if (mRevealAnimator == null) {
|
||||
mRevealAnimator = (ValueAnimator) FolderShape.getShape().createRevealAnimator(this,
|
||||
mRevealAnimator = (ValueAnimator) IconShape.getShape().createRevealAnimator(this,
|
||||
mStartRevealRect, mEndRevealRect, mTaskCornerRadius / scale, !isOpening);
|
||||
mRevealAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user