[DO NOT MERGE] legacy icon treatment / circle detection
Bug: 37357483 Change-Id: I63049ad61ad259f546fcf5077ded0a5f444e4395
This commit is contained in:
parent
46b3a13528
commit
c1cf75716b
|
@ -15,7 +15,7 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:color="#FFE0E0E0"/>
|
<background android:drawable="@color/legacy_icon_background"/>
|
||||||
<foreground>
|
<foreground>
|
||||||
<com.android.launcher3.graphics.FixedScaleDrawable />
|
<com.android.launcher3.graphics.FixedScaleDrawable />
|
||||||
</foreground>
|
</foreground>
|
||||||
|
|
|
@ -45,5 +45,6 @@
|
||||||
<!-- System shortcuts -->
|
<!-- System shortcuts -->
|
||||||
<color name="system_shortcuts_icon_color">@android:color/tertiary_text_light</color>
|
<color name="system_shortcuts_icon_color">@android:color/tertiary_text_light</color>
|
||||||
|
|
||||||
|
<color name="legacy_icon_background">#FFFFFF</color>
|
||||||
<color name="icon_background">#E0E0E0</color> <!-- Gray 300 -->
|
<color name="icon_background">#E0E0E0</color> <!-- Gray 300 -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -767,7 +767,7 @@ public class IconCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class IconDB extends SQLiteCacheHelper {
|
private static final class IconDB extends SQLiteCacheHelper {
|
||||||
private final static int DB_VERSION = 11;
|
private final static int DB_VERSION = 12;
|
||||||
|
|
||||||
private final static int RELEASE_VERSION = DB_VERSION +
|
private final static int RELEASE_VERSION = DB_VERSION +
|
||||||
(FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ? 0 : 1);
|
(FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ? 0 : 1);
|
||||||
|
|
|
@ -19,15 +19,17 @@ public class FixedScaleDrawable extends DrawableWrapper {
|
||||||
|
|
||||||
// TODO b/33553066 use the constant defined in MaskableIconDrawable
|
// TODO b/33553066 use the constant defined in MaskableIconDrawable
|
||||||
private static final float LEGACY_ICON_SCALE = .7f * .6667f;
|
private static final float LEGACY_ICON_SCALE = .7f * .6667f;
|
||||||
|
private float mScale;
|
||||||
|
|
||||||
public FixedScaleDrawable() {
|
public FixedScaleDrawable() {
|
||||||
super(new ColorDrawable());
|
super(new ColorDrawable());
|
||||||
|
mScale = LEGACY_ICON_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(Canvas canvas) {
|
public void draw(Canvas canvas) {
|
||||||
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
|
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
|
||||||
canvas.scale(LEGACY_ICON_SCALE, LEGACY_ICON_SCALE,
|
canvas.scale(mScale, mScale,
|
||||||
getBounds().exactCenterX(), getBounds().exactCenterY());
|
getBounds().exactCenterX(), getBounds().exactCenterY());
|
||||||
super.draw(canvas);
|
super.draw(canvas);
|
||||||
canvas.restoreToCount(saveCount);
|
canvas.restoreToCount(saveCount);
|
||||||
|
@ -38,4 +40,8 @@ public class FixedScaleDrawable extends DrawableWrapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) { }
|
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) { }
|
||||||
|
|
||||||
|
public void setScale(float scale) {
|
||||||
|
mScale = scale * LEGACY_ICON_SCALE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,15 +20,31 @@ import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
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.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.launcher3.LauncherAppState;
|
import com.android.launcher3.LauncherAppState;
|
||||||
|
import com.android.launcher3.Utilities;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class IconNormalizer {
|
public class IconNormalizer {
|
||||||
|
|
||||||
|
private static final String TAG = "IconNormalizer";
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
// Ratio of icon visible area to full icon size for a square shaped icon
|
// Ratio of icon visible area to full icon size for a square shaped icon
|
||||||
private static final float MAX_SQUARE_AREA_FACTOR = 375.0f / 576;
|
private static final float MAX_SQUARE_AREA_FACTOR = 375.0f / 576;
|
||||||
// Ratio of icon visible area to full icon size for a circular shaped icon
|
// Ratio of icon visible area to full icon size for a circular shaped icon
|
||||||
|
@ -42,17 +58,36 @@ public class IconNormalizer {
|
||||||
|
|
||||||
private static final int MIN_VISIBLE_ALPHA = 40;
|
private static final int MIN_VISIBLE_ALPHA = 40;
|
||||||
|
|
||||||
|
// Shape detection related constants
|
||||||
|
private static final float BOUND_RATIO_MARGIN = .05f;
|
||||||
|
private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.005f;
|
||||||
|
private static final float SCALE_NOT_INITIALIZED = 0;
|
||||||
|
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
private static IconNormalizer sIconNormalizer;
|
private static IconNormalizer sIconNormalizer;
|
||||||
|
|
||||||
private final int mMaxSize;
|
private final int mMaxSize;
|
||||||
private final Bitmap mBitmap;
|
private final Bitmap mBitmap;
|
||||||
|
private final Bitmap mBitmapARGB;
|
||||||
private final Canvas mCanvas;
|
private final Canvas mCanvas;
|
||||||
|
private final Paint mPaintMaskShape;
|
||||||
|
private final Paint mPaintMaskShapeOutline;
|
||||||
private final byte[] mPixels;
|
private final byte[] mPixels;
|
||||||
|
private final int[] mPixelsARGB;
|
||||||
|
private float mAdaptiveIconScale;
|
||||||
|
|
||||||
// for each y, stores the position of the leftmost x and the rightmost x
|
// for each y, stores the position of the leftmost x and the rightmost x
|
||||||
private final float[] mLeftBorder;
|
private final float[] mLeftBorder;
|
||||||
private final float[] mRightBorder;
|
private final float[] mRightBorder;
|
||||||
|
private final Rect mBounds;
|
||||||
|
private final Matrix mMatrix;
|
||||||
|
|
||||||
|
private Paint mPaintIcon;
|
||||||
|
private Canvas mCanvasARGB;
|
||||||
|
|
||||||
|
private File mDir;
|
||||||
|
private int mFileId;
|
||||||
|
private Random mRandom;
|
||||||
|
|
||||||
private IconNormalizer(Context context) {
|
private IconNormalizer(Context context) {
|
||||||
// Use twice the icon size as maximum size to avoid scaling down twice.
|
// Use twice the icon size as maximum size to avoid scaling down twice.
|
||||||
|
@ -60,9 +95,121 @@ public class IconNormalizer {
|
||||||
mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
|
mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
|
||||||
mCanvas = new Canvas(mBitmap);
|
mCanvas = new Canvas(mBitmap);
|
||||||
mPixels = new byte[mMaxSize * mMaxSize];
|
mPixels = new byte[mMaxSize * mMaxSize];
|
||||||
|
mPixelsARGB = new int[mMaxSize * mMaxSize];
|
||||||
mLeftBorder = new float[mMaxSize];
|
mLeftBorder = new float[mMaxSize];
|
||||||
mRightBorder = new float[mMaxSize];
|
mRightBorder = new float[mMaxSize];
|
||||||
|
mBounds = new Rect();
|
||||||
|
|
||||||
|
// Needed for isShape() method
|
||||||
|
mBitmapARGB = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ARGB_8888);
|
||||||
|
mCanvasARGB = new Canvas(mBitmapARGB);
|
||||||
|
|
||||||
|
mPaintIcon = new Paint();
|
||||||
|
mPaintIcon.setColor(Color.WHITE);
|
||||||
|
|
||||||
|
mPaintMaskShape = new Paint();
|
||||||
|
mPaintMaskShape.setColor(Color.RED);
|
||||||
|
mPaintMaskShape.setStyle(Paint.Style.FILL);
|
||||||
|
mPaintMaskShape.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
|
||||||
|
|
||||||
|
mPaintMaskShapeOutline = new Paint();
|
||||||
|
mPaintMaskShapeOutline.setStrokeWidth(2 * context.getResources().getDisplayMetrics().density);
|
||||||
|
mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE);
|
||||||
|
mPaintMaskShapeOutline.setColor(Color.BLACK);
|
||||||
|
mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
|
||||||
|
|
||||||
|
mMatrix = new Matrix();
|
||||||
|
int[] mPixels = new int[mMaxSize * mMaxSize];
|
||||||
|
mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
|
||||||
|
|
||||||
|
mDir = context.getExternalFilesDir(null);
|
||||||
|
mRandom = new Random();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the shape of the icon is same as the path.
|
||||||
|
* For this method to work, the shape path bounds should be in [0,1]x[0,1] bounds.
|
||||||
|
*/
|
||||||
|
private boolean isShape(Path maskPath) {
|
||||||
|
// Condition1:
|
||||||
|
// If width and height of the path not close to a square, then the icon shape is
|
||||||
|
// not same as the mask shape.
|
||||||
|
float iconRatio = ((float) mBounds.width()) / mBounds.height();
|
||||||
|
if (Math.abs(iconRatio - 1) > BOUND_RATIO_MARGIN) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Not same as mask shape because width != height. " + iconRatio);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Condition 2:
|
||||||
|
// Actual icon (white) and the fitted shape (e.g., circle)(red) XOR operation
|
||||||
|
// should generate transparent image, if the actual icon is equivalent to the shape.
|
||||||
|
mFileId = mRandom.nextInt();
|
||||||
|
mBitmapARGB.eraseColor(Color.TRANSPARENT);
|
||||||
|
mCanvasARGB.drawBitmap(mBitmap, 0, 0, mPaintIcon);
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
final File beforeFile = new File(mDir, "isShape" + mFileId + "_before.png");
|
||||||
|
try {
|
||||||
|
mBitmapARGB.compress(Bitmap.CompressFormat.PNG, 100,
|
||||||
|
new FileOutputStream(beforeFile));
|
||||||
|
} catch (Exception e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fit the shape within the icon's bounding box
|
||||||
|
mMatrix.reset();
|
||||||
|
mMatrix.setScale(mBounds.width(), mBounds.height());
|
||||||
|
mMatrix.postTranslate(mBounds.left, mBounds.top);
|
||||||
|
maskPath.transform(mMatrix);
|
||||||
|
|
||||||
|
// XOR operation
|
||||||
|
mCanvasARGB.drawPath(maskPath, mPaintMaskShape);
|
||||||
|
|
||||||
|
// DST_OUT operation around the mask path outline
|
||||||
|
mCanvasARGB.drawPath(maskPath, mPaintMaskShapeOutline);
|
||||||
|
|
||||||
|
boolean isTrans = isTransparentBitmap(mBitmapARGB);
|
||||||
|
if (DEBUG) {
|
||||||
|
final File afterFile = new File(mDir, "isShape" + mFileId + "_after_" + isTrans + ".png");
|
||||||
|
try {
|
||||||
|
mBitmapARGB.compress(Bitmap.CompressFormat.PNG, 100,
|
||||||
|
new FileOutputStream(afterFile));
|
||||||
|
} catch (Exception e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the result is almost transparent
|
||||||
|
if (!isTrans) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Not same as mask shape");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to determine if certain the bitmap is transparent.
|
||||||
|
*/
|
||||||
|
private boolean isTransparentBitmap(Bitmap bitmap) {
|
||||||
|
int w = mBounds.width();
|
||||||
|
int h = mBounds.height();
|
||||||
|
bitmap.getPixels(mPixelsARGB, 0 /* the first index to write into the array */,
|
||||||
|
w /* stride */,
|
||||||
|
mBounds.left, mBounds.top,
|
||||||
|
w, h);
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < w * h; i++) {
|
||||||
|
if(Color.alpha(mPixelsARGB[i]) > MIN_VISIBLE_ALPHA) {
|
||||||
|
sum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height());
|
||||||
|
boolean transparentImage = percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD;
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Total # pixel that is different (id="+ mFileId + "):" + percentageDiffPixels + "="+ sum + "/" + mBounds.width() * mBounds.height());
|
||||||
|
}
|
||||||
|
return transparentImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,7 +226,15 @@ public class IconNormalizer {
|
||||||
*
|
*
|
||||||
* @param outBounds optional rect to receive the fraction distance from each edge.
|
* @param outBounds optional rect to receive the fraction distance from each edge.
|
||||||
*/
|
*/
|
||||||
public synchronized float getScale(Drawable d, RectF outBounds) {
|
public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds,
|
||||||
|
@Nullable Path path, @Nullable boolean[] outMaskShape) {
|
||||||
|
if (Utilities.isAtLeastO() && d instanceof AdaptiveIconDrawable &&
|
||||||
|
mAdaptiveIconScale != SCALE_NOT_INITIALIZED) {
|
||||||
|
if (outBounds != null) {
|
||||||
|
outBounds.set(mBounds);
|
||||||
|
}
|
||||||
|
return mAdaptiveIconScale;
|
||||||
|
}
|
||||||
int width = d.getIntrinsicWidth();
|
int width = d.getIntrinsicWidth();
|
||||||
int height = d.getIntrinsicHeight();
|
int height = d.getIntrinsicHeight();
|
||||||
if (width <= 0 || height <= 0) {
|
if (width <= 0 || height <= 0) {
|
||||||
|
@ -169,20 +324,30 @@ public class IconNormalizer {
|
||||||
if (hullByRect < CIRCLE_AREA_BY_RECT) {
|
if (hullByRect < CIRCLE_AREA_BY_RECT) {
|
||||||
scaleRequired = MAX_CIRCLE_AREA_FACTOR;
|
scaleRequired = MAX_CIRCLE_AREA_FACTOR;
|
||||||
} else {
|
} else {
|
||||||
scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect);
|
scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect);
|
||||||
}
|
}
|
||||||
|
mBounds.left = leftX;
|
||||||
|
mBounds.right = rightX;
|
||||||
|
|
||||||
|
mBounds.top = topY;
|
||||||
|
mBounds.bottom = bottomY;
|
||||||
|
|
||||||
if (outBounds != null) {
|
if (outBounds != null) {
|
||||||
outBounds.left = ((float) leftX) / width;
|
outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top),
|
||||||
outBounds.right = 1 - ((float) rightX) / width;
|
1 - ((float) mBounds.right) / width,
|
||||||
|
1 - ((float) mBounds.bottom) / height);
|
||||||
outBounds.top = ((float) topY) / height;
|
|
||||||
outBounds.bottom = 1 - ((float) bottomY) / height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (outMaskShape != null && outMaskShape.length > 0) {
|
||||||
|
outMaskShape[0] = isShape(path);
|
||||||
|
}
|
||||||
float areaScale = area / (width * height);
|
float areaScale = area / (width * height);
|
||||||
// Use sqrt of the final ratio as the images is scaled across both width and 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;
|
float scale = areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
|
||||||
|
if (Utilities.isAtLeastO() && d instanceof AdaptiveIconDrawable &&
|
||||||
|
mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
|
||||||
|
mAdaptiveIconScale = scale;
|
||||||
|
}
|
||||||
return scale;
|
return scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,8 +95,29 @@ public class LauncherIcons {
|
||||||
*/
|
*/
|
||||||
public static Bitmap createBadgedIconBitmap(
|
public static Bitmap createBadgedIconBitmap(
|
||||||
Drawable icon, UserHandle user, Context context) {
|
Drawable icon, UserHandle user, Context context) {
|
||||||
float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
|
|
||||||
1 : IconNormalizer.getInstance(context).getScale(icon, null);
|
IconNormalizer normalizer;
|
||||||
|
float scale = 1f;
|
||||||
|
if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) {
|
||||||
|
normalizer = IconNormalizer.getInstance(context);
|
||||||
|
if (Utilities.isAtLeastO()) {
|
||||||
|
boolean[] outShape = new boolean[1];
|
||||||
|
AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
|
||||||
|
context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
|
||||||
|
dr.setBounds(0, 0, 1, 1);
|
||||||
|
scale = normalizer.getScale(icon, null, dr.getIconMask(), outShape);
|
||||||
|
if (FeatureFlags.LEGACY_ICON_TREATMENT &&
|
||||||
|
!outShape[0]){
|
||||||
|
Drawable wrappedIcon = wrapToAdaptiveIconDrawable(context, icon, scale);
|
||||||
|
if (wrappedIcon != icon) {
|
||||||
|
icon = wrappedIcon;
|
||||||
|
scale = normalizer.getScale(icon, null, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scale = normalizer.getScale(icon, null, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
Bitmap bitmap = createIconBitmap(icon, context, scale);
|
Bitmap bitmap = createIconBitmap(icon, context, scale);
|
||||||
if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.isAtLeastO() &&
|
if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.isAtLeastO() &&
|
||||||
icon instanceof AdaptiveIconDrawable) {
|
icon instanceof AdaptiveIconDrawable) {
|
||||||
|
@ -129,8 +150,29 @@ public class LauncherIcons {
|
||||||
*/
|
*/
|
||||||
public static Bitmap createScaledBitmapWithoutShadow(Drawable icon, Context context) {
|
public static Bitmap createScaledBitmapWithoutShadow(Drawable icon, Context context) {
|
||||||
RectF iconBounds = new RectF();
|
RectF iconBounds = new RectF();
|
||||||
float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
|
IconNormalizer normalizer;
|
||||||
1 : IconNormalizer.getInstance(context).getScale(icon, iconBounds);
|
float scale = 1f;
|
||||||
|
if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) {
|
||||||
|
normalizer = IconNormalizer.getInstance(context);
|
||||||
|
if (Utilities.isAtLeastO()) {
|
||||||
|
boolean[] outShape = new boolean[1];
|
||||||
|
AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
|
||||||
|
context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
|
||||||
|
dr.setBounds(0, 0, 1, 1);
|
||||||
|
scale = normalizer.getScale(icon, iconBounds, dr.getIconMask(), outShape);
|
||||||
|
if (Utilities.isAtLeastO() && FeatureFlags.LEGACY_ICON_TREATMENT &&
|
||||||
|
!outShape[0]) {
|
||||||
|
Drawable wrappedIcon = wrapToAdaptiveIconDrawable(context, icon, scale);
|
||||||
|
if (wrappedIcon != icon) {
|
||||||
|
icon = wrappedIcon;
|
||||||
|
scale = normalizer.getScale(icon, iconBounds, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scale = normalizer.getScale(icon, iconBounds, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
scale = Math.min(scale, ShadowGenerator.getScaleForBounds(iconBounds));
|
scale = Math.min(scale, ShadowGenerator.getScaleForBounds(iconBounds));
|
||||||
return createIconBitmap(icon, context, scale);
|
return createIconBitmap(icon, context, scale);
|
||||||
}
|
}
|
||||||
|
@ -180,10 +222,8 @@ public class LauncherIcons {
|
||||||
* @param scale the scale to apply before drawing {@param icon} on the canvas
|
* @param scale the scale to apply before drawing {@param icon} on the canvas
|
||||||
*/
|
*/
|
||||||
public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
|
public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
|
||||||
icon = wrapToAdaptiveIconDrawable(context, icon);
|
|
||||||
synchronized (sCanvas) {
|
synchronized (sCanvas) {
|
||||||
final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize;
|
final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize;
|
||||||
|
|
||||||
int width = iconBitmapSize;
|
int width = iconBitmapSize;
|
||||||
int height = iconBitmapSize;
|
int height = iconBitmapSize;
|
||||||
|
|
||||||
|
@ -242,7 +282,7 @@ public class LauncherIcons {
|
||||||
* shrink the legacy icon and set it as foreground. Use color drawable as background to
|
* shrink the legacy icon and set it as foreground. Use color drawable as background to
|
||||||
* create AdaptiveIconDrawable.
|
* create AdaptiveIconDrawable.
|
||||||
*/
|
*/
|
||||||
static Drawable wrapToAdaptiveIconDrawable(Context context, Drawable drawable) {
|
static Drawable wrapToAdaptiveIconDrawable(Context context, Drawable drawable, float scale) {
|
||||||
if (!(FeatureFlags.LEGACY_ICON_TREATMENT && Utilities.isAtLeastO())) {
|
if (!(FeatureFlags.LEGACY_ICON_TREATMENT && Utilities.isAtLeastO())) {
|
||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
@ -252,8 +292,10 @@ public class LauncherIcons {
|
||||||
if (!clazz.isAssignableFrom(drawable.getClass())) {
|
if (!clazz.isAssignableFrom(drawable.getClass())) {
|
||||||
Drawable iconWrapper =
|
Drawable iconWrapper =
|
||||||
context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
|
context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
|
||||||
((FixedScaleDrawable) clazz.getMethod("getForeground").invoke(iconWrapper))
|
FixedScaleDrawable fsd = ((FixedScaleDrawable) clazz.getMethod("getForeground")
|
||||||
.setDrawable(drawable);
|
.invoke(iconWrapper));
|
||||||
|
fsd.setDrawable(drawable);
|
||||||
|
fsd.setScale(scale);
|
||||||
|
|
||||||
return iconWrapper;
|
return iconWrapper;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,8 @@ public final class FeatureFlags {
|
||||||
public static final boolean LIGHT_STATUS_BAR = false;
|
public static final boolean LIGHT_STATUS_BAR = false;
|
||||||
// When enabled icons are badged with the number of notifications associated with that app.
|
// When enabled icons are badged with the number of notifications associated with that app.
|
||||||
public static final boolean BADGE_ICONS = true;
|
public static final boolean BADGE_ICONS = true;
|
||||||
// When enabled, icons not supporting {@link MaskableIconDrawable} will be wrapped in this class.
|
// When enabled, icons not supporting {@link AdaptiveIconDrawable} will be wrapped in this class.
|
||||||
public static final boolean LEGACY_ICON_TREATMENT = false;
|
public static final boolean LEGACY_ICON_TREATMENT = true;
|
||||||
// When enabled, adaptive icons would have shadows baked when being stored to icon cache.
|
// When enabled, adaptive icons would have shadows baked when being stored to icon cache.
|
||||||
public static final boolean ADAPTIVE_ICON_SHADOW = true;
|
public static final boolean ADAPTIVE_ICON_SHADOW = true;
|
||||||
// When enabled, app discovery will be enabled if service is implemented
|
// When enabled, app discovery will be enabled if service is implemented
|
||||||
|
|
Loading…
Reference in New Issue