summaryrefslogtreecommitdiff
path: root/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
diff options
context:
space:
mode:
Diffstat (limited to 'iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java')
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java310
1 files changed, 141 insertions, 169 deletions
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index c0be55d..9ce9975 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -2,19 +2,14 @@ package com.android.launcher3.icons;
import static android.graphics.Paint.DITHER_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-import static android.graphics.drawable.AdaptiveIconDrawable.getExtraInsetFraction;
-import static com.android.launcher3.icons.BitmapInfo.FLAG_INSTANT;
-import static com.android.launcher3.icons.BitmapInfo.FLAG_WORK;
import static com.android.launcher3.icons.ShadowGenerator.BLUR_FACTOR;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -27,14 +22,12 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
+import android.os.Process;
import android.os.UserHandle;
-import android.util.SparseBooleanArray;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.android.launcher3.icons.BitmapInfo.Extender;
-import com.android.launcher3.util.FlagOp;
/**
* This class will be moved to androidx library. There shouldn't be any dependency outside
@@ -42,36 +35,35 @@ import com.android.launcher3.util.FlagOp;
*/
public class BaseIconFactory implements AutoCloseable {
+ private static final String TAG = "BaseIconFactory";
private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;
+ static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+ static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
private static final float ICON_BADGE_SCALE = 0.444f;
private final Rect mOldBounds = new Rect();
- private final SparseBooleanArray mIsUserBadged = new SparseBooleanArray();
protected final Context mContext;
private final Canvas mCanvas;
private final PackageManager mPm;
private final ColorExtractor mColorExtractor;
private boolean mDisableColorExtractor;
+ private boolean mBadgeOnLeft = false;
protected final int mFillResIconDpi;
protected final int mIconBitmapSize;
- protected boolean mMonoIconEnabled;
-
private IconNormalizer mNormalizer;
private ShadowGenerator mShadowGenerator;
private final boolean mShapeDetection;
- // Shadow bitmap used as background for theme icons
- private Bitmap mWhiteShadowLayer;
-
private Drawable mWrapperIcon;
private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
+ private Bitmap mUserBadgeBitmap;
private final Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
private static final float PLACEHOLDER_TEXT_SIZE = 20f;
- private static int PLACEHOLDER_BACKGROUND_COLOR = Color.rgb(245, 245, 245);
+ private static int PLACEHOLDER_BACKGROUND_COLOR = Color.rgb(240, 240, 240);
protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
boolean shapeDetection) {
@@ -99,6 +91,7 @@ public class BaseIconFactory implements AutoCloseable {
protected void clear() {
mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
mDisableColorExtractor = false;
+ mBadgeOnLeft = false;
}
public ShadowGenerator getShadowGenerator() {
@@ -122,7 +115,10 @@ public class BaseIconFactory implements AutoCloseable {
if (resources != null) {
final int id = resources.getIdentifier(iconRes.resourceName, null, null);
// do not stamp old legacy shortcuts as the app may have already forgotten about it
- return createBadgedIconBitmap(resources.getDrawableForDensity(id, mFillResIconDpi));
+ return createBadgedIconBitmap(
+ resources.getDrawableForDensity(id, mFillResIconDpi),
+ Process.myUserHandle() /* only available on primary user */,
+ false /* do not apply legacy treatment */);
}
} catch (Exception e) {
// Icon not found.
@@ -138,6 +134,8 @@ public class BaseIconFactory implements AutoCloseable {
* @return
*/
public BitmapInfo createIconBitmap(String placeholder, int color) {
+ if (!ATLEAST_OREO) return null;
+
Bitmap placeholderBitmap = Bitmap.createBitmap(mIconBitmapSize, mIconBitmapSize,
Bitmap.Config.ARGB_8888);
mTextPaint.setColor(color);
@@ -146,7 +144,7 @@ public class BaseIconFactory implements AutoCloseable {
AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
new ColorDrawable(PLACEHOLDER_BACKGROUND_COLOR),
new BitmapDrawable(mContext.getResources(), placeholderBitmap));
- Bitmap icon = createIconBitmap(drawable, IconNormalizer.ICON_VISIBLE_AREA_FACTOR);
+ Bitmap icon = createIconBitmap(drawable, 1f);
return BitmapInfo.of(icon, extractColor(icon));
}
@@ -161,17 +159,43 @@ public class BaseIconFactory implements AutoCloseable {
/**
* Creates an icon from the bitmap cropped to the current device icon shape
*/
- public BitmapInfo createShapedIconBitmap(Bitmap icon, IconOptions options) {
+ public BitmapInfo createShapedIconBitmap(Bitmap icon, UserHandle user) {
Drawable d = new FixedSizeBitmapDrawable(icon);
- float inset = getExtraInsetFraction();
- inset = inset / (1 + 2 * inset);
- d = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK),
- new InsetDrawable(d, inset, inset, inset, inset));
- return createBadgedIconBitmap(d, options);
+ if (ATLEAST_OREO) {
+ float inset = AdaptiveIconDrawable.getExtraInsetFraction();
+ inset = inset / (1 + 2 * inset);
+ d = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK),
+ new InsetDrawable(d, inset, inset, inset, inset));
+ }
+ return createBadgedIconBitmap(d, user, true);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ boolean shrinkNonAdaptiveIcons) {
+ return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, false, null);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ int iconAppTargetSdk) {
+ return createBadgedIconBitmap(icon, user, iconAppTargetSdk, false);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ int iconAppTargetSdk, boolean isInstantApp) {
+ return createBadgedIconBitmap(icon, user, iconAppTargetSdk, isInstantApp, null);
}
- public BitmapInfo createBadgedIconBitmap(@NonNull Drawable icon) {
- return createBadgedIconBitmap(icon, null);
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ int iconAppTargetSdk, boolean isInstantApp, float[] scale) {
+ boolean shrinkNonAdaptiveIcons = ATLEAST_P ||
+ (ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O);
+ return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, isInstantApp, scale);
+ }
+
+ public Bitmap createScaledBitmapWithoutShadow(Drawable icon, int iconAppTargetSdk) {
+ boolean shrinkNonAdaptiveIcons = ATLEAST_P ||
+ (ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O);
+ return createScaledBitmapWithoutShadow(icon, shrinkNonAdaptiveIcons);
}
/**
@@ -179,94 +203,76 @@ public class BaseIconFactory implements AutoCloseable {
* The bitmap is visually normalized with other icons and has enough spacing to add shadow.
*
* @param icon source of the icon
+ * @param user info can be used for a badge
+ * @param shrinkNonAdaptiveIcons {@code true} if non adaptive icons should be treated
+ * @param isInstantApp info can be used for a badge
+ * @param scale returns the scale result from normalization
* @return a bitmap suitable for disaplaying as an icon at various system UIs.
*/
- @TargetApi(Build.VERSION_CODES.TIRAMISU)
- public BitmapInfo createBadgedIconBitmap(@NonNull Drawable icon,
- @Nullable IconOptions options) {
- boolean shrinkNonAdaptiveIcons = options == null || options.mShrinkNonAdaptiveIcons;
- float[] scale = new float[1];
+ public BitmapInfo createBadgedIconBitmap(@NonNull Drawable icon, UserHandle user,
+ boolean shrinkNonAdaptiveIcons, boolean isInstantApp, float[] scale) {
+ if (scale == null) {
+ scale = new float[1];
+ }
icon = normalizeAndWrapToAdaptiveIcon(icon, shrinkNonAdaptiveIcons, null, scale);
Bitmap bitmap = createIconBitmap(icon, scale[0]);
- if (icon instanceof AdaptiveIconDrawable) {
+ if (ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
mCanvas.setBitmap(bitmap);
getShadowGenerator().recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
mCanvas.setBitmap(null);
}
- int color = extractColor(bitmap);
- BitmapInfo info = BitmapInfo.of(bitmap, color);
-
- if (icon instanceof BitmapInfo.Extender) {
- info = ((BitmapInfo.Extender) icon).getExtendedInfo(bitmap, color, this, scale[0]);
- } else if (mMonoIconEnabled && IconProvider.ATLEAST_T
- && icon instanceof AdaptiveIconDrawable) {
- Drawable mono = ((AdaptiveIconDrawable) icon).getMonochrome();
- if (mono != null) {
- // Convert mono drawable to bitmap
- Drawable paddedMono = new ClippedMonoDrawable(mono);
- info.setMonoIcon(
- createIconBitmap(paddedMono, scale[0], mIconBitmapSize, Config.ALPHA_8),
- this);
- }
+ if (isInstantApp) {
+ badgeWithDrawable(bitmap, mContext.getDrawable(R.drawable.ic_instant_app_badge));
}
- info = info.withFlags(getBitmapFlagOp(options));
- return info;
- }
-
- public FlagOp getBitmapFlagOp(@Nullable IconOptions options) {
- FlagOp op = FlagOp.NO_OP;
- if (options != null) {
- if (options.mIsInstantApp) {
- op = op.addFlag(FLAG_INSTANT);
- }
-
- if (options.mUserHandle != null) {
- int key = options.mUserHandle.hashCode();
- boolean isBadged;
- int index;
- if ((index = mIsUserBadged.indexOfKey(key)) >= 0) {
- isBadged = mIsUserBadged.valueAt(index);
- } else {
- // Check packageManager if the provided user needs a badge
- NoopDrawable d = new NoopDrawable();
- isBadged = (d != mPm.getUserBadgedIcon(d, options.mUserHandle));
- mIsUserBadged.put(key, isBadged);
- }
- op = op.setFlag(FLAG_WORK, isBadged);
+ if (user != null) {
+ BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap);
+ Drawable badged = mPm.getUserBadgedIcon(drawable, user);
+ if (badged instanceof BitmapDrawable) {
+ bitmap = ((BitmapDrawable) badged).getBitmap();
+ } else {
+ bitmap = createIconBitmap(badged, 1f);
}
}
- return op;
+ int color = extractColor(bitmap);
+ return icon instanceof BitmapInfo.Extender
+ ? ((BitmapInfo.Extender) icon).getExtendedInfo(bitmap, color, this, scale[0], user)
+ : BitmapInfo.of(bitmap, color);
}
- /** package private */
- Bitmap getWhiteShadowLayer() {
- if (mWhiteShadowLayer == null) {
- mWhiteShadowLayer = createScaledBitmapWithShadow(
- new AdaptiveIconDrawable(new ColorDrawable(Color.WHITE), null));
+ public Bitmap getUserBadgeBitmap(UserHandle user) {
+ if (mUserBadgeBitmap == null) {
+ Bitmap bitmap = Bitmap.createBitmap(
+ mIconBitmapSize, mIconBitmapSize, Bitmap.Config.ARGB_8888);
+ Drawable badgedDrawable = mPm.getUserBadgedIcon(
+ new FixedSizeBitmapDrawable(bitmap), user);
+ if (badgedDrawable instanceof BitmapDrawable) {
+ mUserBadgeBitmap = ((BitmapDrawable) badgedDrawable).getBitmap();
+ } else {
+ badgedDrawable.setBounds(0, 0, mIconBitmapSize, mIconBitmapSize);
+ mUserBadgeBitmap = BitmapRenderer.createSoftwareBitmap(
+ mIconBitmapSize, mIconBitmapSize, badgedDrawable::draw);
+ }
}
- return mWhiteShadowLayer;
- }
-
- /** package private */
- public Bitmap createScaledBitmapWithShadow(Drawable d) {
- float scale = getNormalizer().getScale(d, null, null, null);
- Bitmap bitmap = createIconBitmap(d, scale);
- mCanvas.setBitmap(bitmap);
- getShadowGenerator().recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
- mCanvas.setBitmap(null);
- return bitmap;
+ return mUserBadgeBitmap;
}
- public Bitmap createScaledBitmapWithoutShadow(Drawable icon) {
+ public Bitmap createScaledBitmapWithoutShadow(Drawable icon, boolean shrinkNonAdaptiveIcons) {
RectF iconBounds = new RectF();
float[] scale = new float[1];
- icon = normalizeAndWrapToAdaptiveIcon(icon, true, iconBounds, scale);
+ icon = normalizeAndWrapToAdaptiveIcon(icon, shrinkNonAdaptiveIcons, iconBounds, scale);
return createIconBitmap(icon,
Math.min(scale[0], ShadowGenerator.getScaleForBounds(iconBounds)));
}
/**
+ * Switches badging to left/right
+ */
+ public void setBadgeOnLeft(boolean badgeOnLeft) {
+ mBadgeOnLeft = badgeOnLeft;
+ }
+
+ /**
* Sets the background color used for wrapped adaptive icon
*/
public void setWrapperBackgroundColor(int color) {
@@ -287,7 +293,7 @@ public class BaseIconFactory implements AutoCloseable {
}
float scale = 1f;
- if (shrinkNonAdaptiveIcons && !(icon instanceof AdaptiveIconDrawable)) {
+ if (shrinkNonAdaptiveIcons && ATLEAST_OREO) {
if (mWrapperIcon == null) {
mWrapperIcon = mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper)
.mutate();
@@ -296,12 +302,13 @@ public class BaseIconFactory implements AutoCloseable {
dr.setBounds(0, 0, 1, 1);
boolean[] outShape = new boolean[1];
scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape);
- if (!outShape[0]) {
+ if (!(icon instanceof AdaptiveIconDrawable) && !outShape[0]) {
FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground());
fsd.setDrawable(icon);
fsd.setScale(scale);
icon = dr;
scale = getNormalizer().getScale(icon, outIconBounds, null, null);
+
((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
}
} else {
@@ -312,6 +319,29 @@ public class BaseIconFactory implements AutoCloseable {
return icon;
}
+ /**
+ * Adds the {@param badge} on top of {@param target} using the badge dimensions.
+ */
+ public void badgeWithDrawable(Bitmap target, Drawable badge) {
+ mCanvas.setBitmap(target);
+ badgeWithDrawable(mCanvas, badge);
+ mCanvas.setBitmap(null);
+ }
+
+ /**
+ * Adds the {@param badge} on top of {@param target} using the badge dimensions.
+ */
+ public void badgeWithDrawable(Canvas target, Drawable badge) {
+ int badgeSize = getBadgeSizeForIconSize(mIconBitmapSize);
+ if (mBadgeOnLeft) {
+ badge.setBounds(0, mIconBitmapSize - badgeSize, badgeSize, mIconBitmapSize);
+ } else {
+ badge.setBounds(mIconBitmapSize - badgeSize, mIconBitmapSize - badgeSize,
+ mIconBitmapSize, mIconBitmapSize);
+ }
+ badge.draw(target);
+ }
+
private Bitmap createIconBitmap(Drawable icon, float scale) {
return createIconBitmap(icon, scale, mIconBitmapSize);
}
@@ -321,32 +351,22 @@ public class BaseIconFactory implements AutoCloseable {
* @param scale the scale to apply before drawing {@param icon} on the canvas
*/
public Bitmap createIconBitmap(@NonNull Drawable icon, float scale, int size) {
- return createIconBitmap(icon, scale, size, Bitmap.Config.ARGB_8888);
- }
-
- private Bitmap createIconBitmap(@NonNull Drawable icon, float scale, int size,
- Bitmap.Config config) {
- Bitmap bitmap = Bitmap.createBitmap(size, size, config);
+ Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
if (icon == null) {
return bitmap;
}
mCanvas.setBitmap(bitmap);
mOldBounds.set(icon.getBounds());
- if (icon instanceof AdaptiveIconDrawable) {
+ if (ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
int offset = Math.max((int) Math.ceil(BLUR_FACTOR * size),
Math.round(size * (1 - scale) / 2 ));
- // b/211896569: AdaptiveIconDrawable do not work properly for non top-left bounds
- icon.setBounds(0, 0, size - offset - offset, size - offset - offset);
- int count = mCanvas.save();
- mCanvas.translate(offset, offset);
-
+ icon.setBounds(offset, offset, size - offset, size - offset);
if (icon instanceof BitmapInfo.Extender) {
((Extender) icon).drawForPersistence(mCanvas);
} else {
icon.draw(mCanvas);
}
- mCanvas.restoreToCount(count);
} else {
if (icon instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
@@ -388,13 +408,27 @@ public class BaseIconFactory implements AutoCloseable {
clear();
}
- public BitmapInfo makeDefaultIcon() {
- return createBadgedIconBitmap(getFullResDefaultActivityIcon(mFillResIconDpi));
+ public BitmapInfo makeDefaultIcon(UserHandle user) {
+ return createBadgedIconBitmap(getFullResDefaultActivityIcon(mFillResIconDpi),
+ user, Build.VERSION.SDK_INT);
}
public static Drawable getFullResDefaultActivityIcon(int iconDpi) {
return Resources.getSystem().getDrawableForDensity(
- android.R.drawable.sym_def_app_icon, iconDpi);
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+ ? android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon,
+ iconDpi);
+ }
+
+ /**
+ * Badges the provided source with the badge info
+ */
+ public BitmapInfo badgeBitmap(Bitmap source, BitmapInfo badgeInfo) {
+ Bitmap icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> {
+ getShadowGenerator().recreateIcon(source, c);
+ badgeWithDrawable(c, new FixedSizeBitmapDrawable(badgeInfo.icon));
+ });
+ return BitmapInfo.of(icon, badgeInfo.color);
}
private int extractColor(Bitmap bitmap) {
@@ -408,37 +442,6 @@ public class BaseIconFactory implements AutoCloseable {
return (int) (ICON_BADGE_SCALE * iconSize);
}
- public static class IconOptions {
-
- boolean mShrinkNonAdaptiveIcons = true;
- boolean mIsInstantApp;
- UserHandle mUserHandle;
-
- /**
- * Set to false if non-adaptive icons should not be treated
- */
- public IconOptions setShrinkNonAdaptiveIcons(boolean shrink) {
- mShrinkNonAdaptiveIcons = shrink;
- return this;
- }
-
- /**
- * User for this icon, in case of badging
- */
- public IconOptions setUser(UserHandle user) {
- mUserHandle = user;
- return this;
- }
-
- /**
- * If this icon represents an instant app
- */
- public IconOptions setInstantApp(boolean instantApp) {
- mIsInstantApp = instantApp;
- return this;
- }
- }
-
/**
* An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size.
* This allows the badging to be done based on the action bitmap size rather than
@@ -460,35 +463,4 @@ public class BaseIconFactory implements AutoCloseable {
return getBitmap().getWidth();
}
}
-
- private static class NoopDrawable extends ColorDrawable {
- @Override
- public int getIntrinsicHeight() {
- return 1;
- }
-
- @Override
- public int getIntrinsicWidth() {
- return 1;
- }
- }
-
- private static class ClippedMonoDrawable extends InsetDrawable {
-
- private final AdaptiveIconDrawable mCrop;
-
- public ClippedMonoDrawable(Drawable base) {
- super(base, -getExtraInsetFraction());
- mCrop = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null);
- }
-
- @Override
- public void draw(Canvas canvas) {
- mCrop.setBounds(getBounds());
- int saveCount = canvas.save();
- canvas.clipPath(mCrop.getIconMask());
- super.draw(canvas);
- canvas.restoreToCount(saveCount);
- }
- }
}