diff options
Diffstat (limited to 'iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java')
-rw-r--r-- | iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java | 310 |
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); - } - } } |