summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--iconloaderlib/build.gradle2
-rw-r--r--iconloaderlib/res/drawable/ic_work_app_badge.xml39
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java310
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java159
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java325
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java11
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java148
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java2
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/IconProvider.java174
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java6
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.java254
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java282
-rw-r--r--iconloaderlib/src/com/android/launcher3/util/FlagOp.java48
-rw-r--r--searchuilib/build.gradle2
-rw-r--r--searchuilib/src/com/android/app/search/LayoutType.java5
-rw-r--r--searchuilib/src/com/android/app/search/ResultType.java50
16 files changed, 753 insertions, 1064 deletions
diff --git a/iconloaderlib/build.gradle b/iconloaderlib/build.gradle
index 10ec889..8410275 100644
--- a/iconloaderlib/build.gradle
+++ b/iconloaderlib/build.gradle
@@ -7,6 +7,8 @@ android {
defaultConfig {
minSdkVersion 26
targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
}
sourceSets {
diff --git a/iconloaderlib/res/drawable/ic_work_app_badge.xml b/iconloaderlib/res/drawable/ic_work_app_badge.xml
deleted file mode 100644
index 1599489..0000000
--- a/iconloaderlib/res/drawable/ic_work_app_badge.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/profile_badge_size"
- android:height="@dimen/profile_badge_size"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:fillColor="#11000000"
- android:pathData="M.5,12.25
- A11.5,11.5 0 1,1 23.5,12.25
- A11.5,11.5 0 1,1 .5,12.25" />
-
- <path
- android:fillColor="@android:color/white"
- android:pathData="M1,12
- A11,11 0 1,1 23,12
- A11,11 0 1,1 1,12" />
-
- <group android:scaleX=".6" android:scaleY=".6" android:pivotX="12" android:pivotY="12">
- <path
- android:fillColor="#1A73E8"
- android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2z" />
- </group>
-</vector>
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);
- }
- }
}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java b/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
index c3ca42e..06b39b8 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
@@ -15,91 +15,45 @@
*/
package com.android.launcher3.icons;
+import static com.android.launcher3.icons.GraphicsUtils.getExpectedBitmapSize;
+
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.UserHandle;
+import android.util.Log;
-import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.util.FlagOp;
+import com.android.launcher3.icons.ThemedIconDrawable.ThemedBitmapInfo;
+import com.android.launcher3.icons.cache.BaseIconCache;
-public class BitmapInfo {
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
- static final int FLAG_WORK = 1 << 0;
- static final int FLAG_INSTANT = 1 << 1;
- @IntDef(flag = true, value = {
- FLAG_WORK,
- FLAG_INSTANT,
- })
- @interface BitmapInfoFlags {}
-
- public static final int FLAG_THEMED = 1 << 0;
- public static final int FLAG_NO_BADGE = 1 << 1;
- @IntDef(flag = true, value = {
- FLAG_THEMED,
- FLAG_NO_BADGE,
- })
- public @interface DrawableCreationFlags {}
+public class BitmapInfo {
public static final Bitmap LOW_RES_ICON = Bitmap.createBitmap(1, 1, Config.ALPHA_8);
public static final BitmapInfo LOW_RES_INFO = fromBitmap(LOW_RES_ICON);
public static final String TAG = "BitmapInfo";
+ protected static final byte TYPE_DEFAULT = 1;
+ protected static final byte TYPE_THEMED = 2;
+
public final Bitmap icon;
public final int color;
- @Nullable
- protected Bitmap mMono;
- protected Bitmap mWhiteShadowLayer;
-
- public @BitmapInfoFlags int flags;
- private BitmapInfo badgeInfo;
-
public BitmapInfo(Bitmap icon, int color) {
this.icon = icon;
this.color = color;
}
- public BitmapInfo withBadgeInfo(BitmapInfo badgeInfo) {
- BitmapInfo result = clone();
- result.badgeInfo = badgeInfo;
- return result;
- }
-
- /**
- * Returns a bitmapInfo with the flagOP applied
- */
- public BitmapInfo withFlags(@NonNull FlagOp op) {
- if (op == FlagOp.NO_OP) {
- return this;
- }
- BitmapInfo result = clone();
- result.flags = op.apply(result.flags);
- return result;
- }
-
- protected BitmapInfo copyInternalsTo(BitmapInfo target) {
- target.mMono = mMono;
- target.mWhiteShadowLayer = mWhiteShadowLayer;
- target.flags = flags;
- target.badgeInfo = badgeInfo;
- return target;
- }
-
- @Override
- public BitmapInfo clone() {
- return copyInternalsTo(new BitmapInfo(icon, color));
- }
-
- public void setMonoIcon(Bitmap mono, BaseIconFactory iconFactory) {
- mMono = mono;
- mWhiteShadowLayer = iconFactory.getWhiteShadowLayer();
- }
-
/**
* Ideally icon should not be null, except in cases when generating hardware bitmap failed
*/
@@ -112,50 +66,68 @@ public class BitmapInfo {
}
/**
- * BitmapInfo can be stored on disk or other persistent storage
+ * Returns a serialized version of BitmapInfo
*/
- public boolean canPersist() {
- return !isNullOrLowRes();
+ @Nullable
+ public byte[] toByteArray() {
+ if (isNullOrLowRes()) {
+ return null;
+ }
+ ByteArrayOutputStream out = new ByteArrayOutputStream(getExpectedBitmapSize(icon) + 1);
+ try {
+ out.write(TYPE_DEFAULT);
+ icon.compress(Bitmap.CompressFormat.PNG, 100, out);
+ out.flush();
+ out.close();
+ return out.toByteArray();
+ } catch (IOException e) {
+ Log.w(TAG, "Could not write bitmap");
+ return null;
+ }
}
- public Bitmap getMono() {
- return mMono;
+ /**
+ * Returns a new icon based on the theme of the context
+ */
+ public FastBitmapDrawable newThemedIcon(Context context) {
+ return newIcon(context);
}
/**
* Creates a drawable for the provided BitmapInfo
*/
public FastBitmapDrawable newIcon(Context context) {
- return newIcon(context, 0);
+ FastBitmapDrawable drawable = isLowRes()
+ ? new PlaceHolderIconDrawable(this, context)
+ : new FastBitmapDrawable(this);
+ drawable.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f);
+ return drawable;
}
/**
- * Creates a drawable for the provided BitmapInfo
+ * Returns a BitmapInfo previously serialized using {@link #toByteArray()};
*/
- public FastBitmapDrawable newIcon(Context context, @DrawableCreationFlags int creationFlags) {
- FastBitmapDrawable drawable;
- if (isLowRes()) {
- drawable = new PlaceHolderIconDrawable(this, context);
- } else if ((creationFlags & FLAG_THEMED) != 0 && mMono != null) {
- drawable = ThemedIconDrawable.newDrawable(this, context);
+ @NonNull
+ public static BitmapInfo fromByteArray(byte[] data, int color, UserHandle user,
+ BaseIconCache iconCache, Context context) {
+ if (data == null) {
+ return null;
+ }
+ BitmapFactory.Options decodeOptions;
+ if (BitmapRenderer.USE_HARDWARE_BITMAP && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ decodeOptions = new BitmapFactory.Options();
+ decodeOptions.inPreferredConfig = Bitmap.Config.HARDWARE;
} else {
- drawable = new FastBitmapDrawable(this);
+ decodeOptions = null;
}
- applyFlags(context, drawable, creationFlags);
- return drawable;
- }
-
- protected void applyFlags(Context context, FastBitmapDrawable drawable,
- @DrawableCreationFlags int creationFlags) {
- drawable.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f);
- if ((creationFlags & FLAG_NO_BADGE) == 0) {
- if (badgeInfo != null) {
- drawable.setBadge(badgeInfo.newIcon(context, creationFlags));
- } else if ((flags & FLAG_INSTANT) != 0) {
- drawable.setBadge(context.getDrawable(R.drawable.ic_instant_app_badge));
- } else if ((flags & FLAG_WORK) != 0) {
- drawable.setBadge(context.getDrawable(R.drawable.ic_work_app_badge));
- }
+ if (data[0] == TYPE_DEFAULT) {
+ return BitmapInfo.of(
+ BitmapFactory.decodeByteArray(data, 1, data.length - 1, decodeOptions),
+ color);
+ } else if (data[0] == TYPE_THEMED) {
+ return ThemedBitmapInfo.decode(data, color, decodeOptions, user, iconCache, context);
+ } else {
+ return null;
}
}
@@ -176,11 +148,16 @@ public class BitmapInfo {
* Called for creating a custom BitmapInfo
*/
BitmapInfo getExtendedInfo(Bitmap bitmap, int color,
- BaseIconFactory iconFactory, float normalizationScale);
+ BaseIconFactory iconFactory, float normalizationScale, UserHandle user);
/**
* Called to draw the UI independent of any runtime configurations like time or theme
*/
void drawForPersistence(Canvas canvas);
+
+ /**
+ * Returns a new icon with theme applied
+ */
+ Drawable getThemedDrawable(Context context);
}
}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java b/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java
index d624805..a7894c9 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java
@@ -15,7 +15,7 @@
*/
package com.android.launcher3.icons;
-import static com.android.launcher3.icons.IconProvider.ATLEAST_T;
+import static com.android.launcher3.icons.ThemedIconDrawable.getColors;
import android.annotation.TargetApi;
import android.content.Context;
@@ -24,12 +24,13 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.BlendMode;
-import android.graphics.BlendModeColorFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.ColorDrawable;
@@ -37,13 +38,15 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.os.Bundle;
+import android.os.Process;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.Log;
import android.util.TypedValue;
import androidx.annotation.Nullable;
-import com.android.launcher3.icons.IconProvider.ThemeData;
+import com.android.launcher3.icons.ThemedIconDrawable.ThemeData;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
@@ -59,7 +62,6 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
private static final String TAG = "ClockDrawableWrapper";
private static final boolean DISABLE_SECONDS = true;
- private static final int NO_COLOR = -1;
// Time after which the clock icon should check for an update. The actual invalidate
// will only happen in case of any change.
@@ -86,16 +88,32 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
public static final int INVALID_VALUE = -1;
private final AnimationInfo mAnimationInfo = new AnimationInfo();
- private AnimationInfo mThemeInfo = null;
+ private int mTargetSdkVersion;
+ protected ThemeData mThemeData;
- private ClockDrawableWrapper(AdaptiveIconDrawable base) {
+ public ClockDrawableWrapper(AdaptiveIconDrawable base) {
super(base.getBackground(), base.getForeground());
}
- private void applyThemeData(ThemeData themeData) {
- if (!IconProvider.ATLEAST_T || mThemeInfo != null) {
- return;
+ /**
+ * Loads and returns the wrapper from the provided package, or returns null
+ * if it is unable to load.
+ */
+ public static ClockDrawableWrapper forPackage(Context context, String pkg, int iconDpi) {
+ try {
+ PackageManager pm = context.getPackageManager();
+ ApplicationInfo appInfo = pm.getApplicationInfo(pkg,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
+ Resources res = pm.getResourcesForApplication(appInfo);
+ return forExtras(appInfo, appInfo.metaData,
+ resId -> res.getDrawableForDensity(resId, iconDpi));
+ } catch (Exception e) {
+ Log.d(TAG, "Unable to load clock drawable info", e);
}
+ return null;
+ }
+
+ private static ClockDrawableWrapper fromThemeData(Context context, ThemeData themeData) {
try {
TypedArray ta = themeData.mResources.obtainTypedArray(themeData.mResID);
int count = ta.length();
@@ -107,59 +125,25 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
? v.data : v.resourceId);
}
ta.recycle();
- ClockDrawableWrapper drawable = ClockDrawableWrapper.forExtras(extras, resId -> {
- Drawable bg = new ColorDrawable(Color.WHITE);
- Drawable fg = themeData.mResources.getDrawable(resId).mutate();
- return new AdaptiveIconDrawable(bg, fg);
- });
+ ClockDrawableWrapper drawable = ClockDrawableWrapper.forExtras(
+ context.getApplicationInfo(), extras, resId -> {
+ int[] colors = getColors(context);
+ Drawable bg = new ColorDrawable(colors[0]);
+ Drawable fg = themeData.mResources.getDrawable(resId).mutate();
+ fg.setTint(colors[1]);
+ return new AdaptiveIconDrawable(bg, fg);
+ });
if (drawable != null) {
- mThemeInfo = drawable.mAnimationInfo;
+ return drawable;
}
} catch (Exception e) {
Log.e(TAG, "Error loading themed clock", e);
}
- }
-
- @Override
- public Drawable getMonochrome() {
- if (mThemeInfo == null) {
- return null;
- }
- Drawable d = mThemeInfo.baseDrawableState.newDrawable().mutate();
- if (d instanceof AdaptiveIconDrawable) {
- Drawable mono = ((AdaptiveIconDrawable) d).getForeground();
- mThemeInfo.applyTime(Calendar.getInstance(), (LayerDrawable) mono);
- return mono;
- }
return null;
}
- /**
- * Loads and returns the wrapper from the provided package, or returns null
- * if it is unable to load.
- */
- public static ClockDrawableWrapper forPackage(Context context, String pkg, int iconDpi,
- @Nullable ThemeData themeData) {
- try {
- PackageManager pm = context.getPackageManager();
- ApplicationInfo appInfo = pm.getApplicationInfo(pkg,
- PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
- Resources res = pm.getResourcesForApplication(appInfo);
- ClockDrawableWrapper wrapper = forExtras(appInfo.metaData,
- resId -> res.getDrawableForDensity(resId, iconDpi));
- if (wrapper != null && themeData != null) {
- wrapper.applyThemeData(themeData);
- }
- return wrapper;
- } catch (Exception e) {
- Log.d(TAG, "Unable to load clock drawable info", e);
- }
- return null;
- }
-
- @TargetApi(Build.VERSION_CODES.TIRAMISU)
- private static ClockDrawableWrapper forExtras(
- Bundle metadata, IntFunction<Drawable> drawableProvider) {
+ private static ClockDrawableWrapper forExtras(ApplicationInfo appInfo, Bundle metadata,
+ IntFunction<Drawable> drawableProvider) {
if (metadata == null) {
return null;
}
@@ -172,12 +156,14 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
if (!(drawable instanceof AdaptiveIconDrawable)) {
return null;
}
- AdaptiveIconDrawable aid = (AdaptiveIconDrawable) drawable;
- ClockDrawableWrapper wrapper = new ClockDrawableWrapper(aid);
+ ClockDrawableWrapper wrapper =
+ new ClockDrawableWrapper((AdaptiveIconDrawable) drawable);
+ wrapper.mTargetSdkVersion = appInfo.targetSdkVersion;
AnimationInfo info = wrapper.mAnimationInfo;
info.baseDrawableState = drawable.getConstantState();
+
info.hourLayerIndex = metadata.getInt(HOUR_INDEX_METADATA_KEY, INVALID_VALUE);
info.minuteLayerIndex = metadata.getInt(MINUTE_INDEX_METADATA_KEY, INVALID_VALUE);
info.secondLayerIndex = metadata.getInt(SECOND_INDEX_METADATA_KEY, INVALID_VALUE);
@@ -200,27 +186,21 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
foreground.setDrawable(info.secondLayerIndex, null);
info.secondLayerIndex = INVALID_VALUE;
}
-
- if (ATLEAST_T && aid.getMonochrome() instanceof LayerDrawable) {
- wrapper.mThemeInfo = info.copyForIcon(new AdaptiveIconDrawable(
- new ColorDrawable(Color.WHITE), aid.getMonochrome().mutate()));
- }
info.applyTime(Calendar.getInstance(), foreground);
return wrapper;
}
@Override
public ClockBitmapInfo getExtendedInfo(Bitmap bitmap, int color,
- BaseIconFactory iconFactory, float normalizationScale) {
+ BaseIconFactory iconFactory, float normalizationScale, UserHandle user) {
+ iconFactory.disableColorExtraction();
AdaptiveIconDrawable background = new AdaptiveIconDrawable(
getBackground().getConstantState().newDrawable(), null);
- Bitmap flattenBG = iconFactory.createScaledBitmapWithShadow(background);
+ BitmapInfo bitmapInfo = iconFactory.createBadgedIconBitmap(background,
+ Process.myUserHandle(), mTargetSdkVersion, false);
- // Only pass theme info if mono-icon is enabled
- AnimationInfo themeInfo = iconFactory.mMonoIconEnabled ? mThemeInfo : null;
- Bitmap themeBG = themeInfo == null ? null : iconFactory.getWhiteShadowLayer();
return new ClockBitmapInfo(bitmap, color, normalizationScale,
- mAnimationInfo, flattenBG, themeInfo, themeBG);
+ mAnimationInfo, bitmapInfo.icon, mThemeData);
}
@Override
@@ -233,6 +213,15 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
mAnimationInfo.applyTime(Calendar.getInstance(), (LayerDrawable) getForeground());
}
+ @Override
+ public Drawable getThemedDrawable(Context context) {
+ if (mThemeData != null) {
+ ClockDrawableWrapper drawable = fromThemeData(context, mThemeData);
+ return drawable == null ? this : drawable;
+ }
+ return this;
+ }
+
private void resetLevel(LayerDrawable drawable, int index) {
if (index != INVALID_VALUE) {
drawable.getDrawable(index).setLevel(0);
@@ -250,18 +239,6 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
public int defaultMinute;
public int defaultSecond;
- public AnimationInfo copyForIcon(Drawable icon) {
- AnimationInfo result = new AnimationInfo();
- result.baseDrawableState = icon.getConstantState();
- result.defaultHour = defaultHour;
- result.defaultMinute = defaultMinute;
- result.defaultSecond = defaultSecond;
- result.hourLayerIndex = hourLayerIndex;
- result.minuteLayerIndex = minuteLayerIndex;
- result.secondLayerIndex = secondLayerIndex;
- return result;
- }
-
boolean applyTime(Calendar time, LayerDrawable foregroundDrawable) {
time.setTimeInMillis(System.currentTimeMillis());
@@ -298,66 +275,66 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
static class ClockBitmapInfo extends BitmapInfo {
- public final float boundsOffset;
-
+ public final float scale;
+ public final int offset;
public final AnimationInfo animInfo;
public final Bitmap mFlattenedBackground;
- public final AnimationInfo themeData;
- public final Bitmap themeBackground;
+ public final ThemeData themeData;
+ public final ColorFilter bgFilter;
+
+ ClockBitmapInfo(Bitmap icon, int color, float scale, AnimationInfo animInfo,
+ Bitmap background, ThemeData themeData) {
+ this(icon, color, scale, animInfo, background, themeData, null);
+ }
- ClockBitmapInfo(Bitmap icon, int color, float scale,
- AnimationInfo animInfo, Bitmap background,
- AnimationInfo themeInfo, Bitmap themeBackground) {
+ ClockBitmapInfo(Bitmap icon, int color, float scale, AnimationInfo animInfo,
+ Bitmap background, ThemeData themeData, ColorFilter bgFilter) {
super(icon, color);
- this.boundsOffset = Math.max(ShadowGenerator.BLUR_FACTOR, (1 - scale) / 2);
+ this.scale = scale;
this.animInfo = animInfo;
+ this.offset = (int) Math.ceil(ShadowGenerator.BLUR_FACTOR * icon.getWidth());
this.mFlattenedBackground = background;
- this.themeData = themeInfo;
- this.themeBackground = themeBackground;
+ this.themeData = themeData;
+ this.bgFilter = bgFilter;
}
@Override
- @TargetApi(Build.VERSION_CODES.TIRAMISU)
- public FastBitmapDrawable newIcon(Context context,
- @DrawableCreationFlags int creationFlags) {
- AnimationInfo info;
- Bitmap bg;
- int themedFgColor;
- ColorFilter bgFilter;
- if ((creationFlags & FLAG_THEMED) != 0 && themeData != null) {
- int[] colors = ThemedIconDrawable.getColors(context);
- Drawable tintedDrawable = themeData.baseDrawableState.newDrawable().mutate();
- themedFgColor = colors[1];
- tintedDrawable.setTint(colors[1]);
- info = themeData.copyForIcon(tintedDrawable);
- bg = themeBackground;
- bgFilter = new BlendModeColorFilter(colors[0], BlendMode.SRC_IN);
- } else {
- info = animInfo;
- themedFgColor = NO_COLOR;
- bg = mFlattenedBackground;
- bgFilter = null;
- }
- if (info == null) {
- return super.newIcon(context, creationFlags);
+ public FastBitmapDrawable newThemedIcon(Context context) {
+ if (themeData != null) {
+ ClockDrawableWrapper wrapper = fromThemeData(context, themeData);
+ if (wrapper != null) {
+ int[] colors = getColors(context);
+ ColorFilter bgFilter = new PorterDuffColorFilter(colors[0], Mode.SRC_ATOP);
+ return new ClockBitmapInfo(icon, colors[1], scale,
+ wrapper.mAnimationInfo, mFlattenedBackground, themeData, bgFilter)
+ .newIcon(context);
+ }
}
- ClockIconDrawable.ClockConstantState cs = new ClockIconDrawable.ClockConstantState(
- icon, color, themedFgColor, boundsOffset, info, bg, bgFilter);
- FastBitmapDrawable d = cs.newDrawable();
- applyFlags(context, d, creationFlags);
- return d;
+ return super.newThemedIcon(context);
}
@Override
- public boolean canPersist() {
- return false;
+ public FastBitmapDrawable newIcon(Context context) {
+ ClockIconDrawable d = new ClockIconDrawable(this);
+ d.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f);
+ return d;
}
+ @Nullable
@Override
- public BitmapInfo clone() {
- return copyInternalsTo(new ClockBitmapInfo(icon, color, 1 - 2 * boundsOffset, animInfo,
- mFlattenedBackground, themeData, themeBackground));
+ public byte[] toByteArray() {
+ return null;
+ }
+
+ void drawBackground(Canvas canvas, Rect bounds, Paint paint) {
+ // draw the background that is already flattened to a bitmap
+ ColorFilter oldFilter = paint.getColorFilter();
+ if (bgFilter != null) {
+ paint.setColorFilter(bgFilter);
+ }
+ canvas.drawBitmap(mFlattenedBackground, null, bounds, paint);
+ paint.setColorFilter(oldFilter);
}
}
@@ -365,89 +342,59 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
private final Calendar mTime = Calendar.getInstance();
- private final float mBoundsOffset;
- private final AnimationInfo mAnimInfo;
-
- private final Bitmap mBG;
- private final Paint mBgPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
- private final ColorFilter mBgFilter;
- private final int mThemedFgColor;
+ private final ClockBitmapInfo mInfo;
private final AdaptiveIconDrawable mFullDrawable;
- private final LayerDrawable mFG;
- private final float mCanvasScale;
-
- ClockIconDrawable(ClockConstantState cs) {
- super(cs.mBitmap, cs.mIconColor);
- mBoundsOffset = cs.mBoundsOffset;
- mAnimInfo = cs.mAnimInfo;
-
- mBG = cs.mBG;
- mBgFilter = cs.mBgFilter;
- mBgPaint.setColorFilter(cs.mBgFilter);
- mThemedFgColor = cs.mThemedFgColor;
-
- mFullDrawable = (AdaptiveIconDrawable) mAnimInfo.baseDrawableState.newDrawable();
- mFG = (LayerDrawable) mFullDrawable.getForeground();
-
- // Time needs to be applied here since drawInternal is NOT guaranteed to be called
- // before this foreground drawable is shown on the screen.
- mAnimInfo.applyTime(mTime, mFG);
- mCanvasScale = 1 - 2 * mBoundsOffset;
+ private final LayerDrawable mForeground;
+
+ ClockIconDrawable(ClockBitmapInfo clockInfo) {
+ super(clockInfo);
+
+ mInfo = clockInfo;
+ mFullDrawable = (AdaptiveIconDrawable) mInfo.animInfo.baseDrawableState
+ .newDrawable().mutate();
+ mForeground = (LayerDrawable) mFullDrawable.getForeground();
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
-
- // b/211896569 AdaptiveIcon does not work properly when bounds
- // are not aligned to top/left corner
- mFullDrawable.setBounds(0, 0, bounds.width(), bounds.height());
+ mFullDrawable.setBounds(bounds);
}
@Override
public void drawInternal(Canvas canvas, Rect bounds) {
- if (mAnimInfo == null) {
+ if (mInfo == null) {
super.drawInternal(canvas, bounds);
return;
}
- canvas.drawBitmap(mBG, null, bounds, mBgPaint);
+ mInfo.drawBackground(canvas, bounds, mPaint);
// prepare and draw the foreground
- mAnimInfo.applyTime(mTime, mFG);
- int saveCount = canvas.save();
- canvas.translate(bounds.left, bounds.top);
- canvas.scale(mCanvasScale, mCanvasScale, bounds.width() / 2, bounds.height() / 2);
+ mInfo.animInfo.applyTime(mTime, mForeground);
+
+ canvas.scale(mInfo.scale, mInfo.scale,
+ bounds.exactCenterX() + mInfo.offset, bounds.exactCenterY() + mInfo.offset);
canvas.clipPath(mFullDrawable.getIconMask());
- mFG.draw(canvas);
- canvas.restoreToCount(saveCount);
+ mForeground.draw(canvas);
reschedule();
}
@Override
public boolean isThemed() {
- return mBgPaint.getColorFilter() != null;
+ return mInfo.bgFilter != null;
}
@Override
protected void updateFilter() {
super.updateFilter();
- int alpha = mIsDisabled ? (int) (mDisabledAlpha * FULLY_OPAQUE) : FULLY_OPAQUE;
- mBgPaint.setAlpha(alpha);
- mFG.setAlpha(alpha);
- mBgPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : mBgFilter);
- mFG.setColorFilter(mIsDisabled ? getDisabledColorFilter() : null);
- }
-
- @Override
- public int getIconColor() {
- return isThemed() ? mThemedFgColor : super.getIconColor();
+ mFullDrawable.setColorFilter(mPaint.getColorFilter());
}
@Override
public void run() {
- if (mAnimInfo.applyTime(mTime, mFG)) {
+ if (mInfo.animInfo.applyTime(mTime, mForeground)) {
invalidateSelf();
} else {
reschedule();
@@ -477,32 +424,24 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
}
@Override
- public FastBitmapConstantState newConstantState() {
- return new ClockConstantState(mBitmap, mIconColor, mThemedFgColor, mBoundsOffset,
- mAnimInfo, mBG, mBgPaint.getColorFilter());
+ public ConstantState getConstantState() {
+ return new ClockConstantState(mInfo, isDisabled());
}
private static class ClockConstantState extends FastBitmapConstantState {
- private final float mBoundsOffset;
- private final AnimationInfo mAnimInfo;
- private final Bitmap mBG;
- private final ColorFilter mBgFilter;
- private final int mThemedFgColor;
-
- ClockConstantState(Bitmap bitmap, int color, int themedFgColor,
- float boundsOffset, AnimationInfo animInfo, Bitmap bg, ColorFilter bgFilter) {
- super(bitmap, color);
- mBoundsOffset = boundsOffset;
- mAnimInfo = animInfo;
- mBG = bg;
- mBgFilter = bgFilter;
- mThemedFgColor = themedFgColor;
+ private final ClockBitmapInfo mInfo;
+
+ ClockConstantState(ClockBitmapInfo info, boolean isDisabled) {
+ super(info.icon, info.color, isDisabled);
+ mInfo = info;
}
@Override
- public FastBitmapDrawable createDrawable() {
- return new ClockIconDrawable(this);
+ public FastBitmapDrawable newDrawable() {
+ ClockIconDrawable drawable = new ClockIconDrawable(mInfo);
+ drawable.setIsDisabled(mIsDisabled);
+ return drawable;
}
}
}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java
index a42232e..97a0fd3 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java
@@ -50,12 +50,8 @@ public class DotRenderer {
private final float[] mRightDotPosition;
private final float[] mLeftDotPosition;
- private static final int MIN_DOT_SIZE = 1;
public DotRenderer(int iconSizePx, Path iconShapePath, int pathSize) {
int size = Math.round(SIZE_PERCENTAGE * iconSizePx);
- if (size <= 0) {
- size = MIN_DOT_SIZE;
- }
ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT);
builder.ambientShadowAlpha = 88;
mBackgroundWithShadow = builder.setupBlurForSize(size).createPill(size, size);
@@ -125,7 +121,7 @@ public class DotRenderer {
mCirclePaint.setColor(Color.BLACK);
canvas.drawBitmap(mBackgroundWithShadow, mBitmapOffset, mBitmapOffset, mCirclePaint);
- mCirclePaint.setColor(params.dotColor);
+ mCirclePaint.setColor(params.color);
canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint);
canvas.restore();
}
@@ -133,10 +129,7 @@ public class DotRenderer {
public static class DrawParams {
/** The color (possibly based on the icon) to use for the dot. */
@ViewDebug.ExportedProperty(category = "notification dot", formatToHexString = true)
- public int dotColor;
- /** The color (possibly based on the icon) to use for a predicted app. */
- @ViewDebug.ExportedProperty(category = "notification dot", formatToHexString = true)
- public int appColor;
+ public int color;
/** The bounds of the icon that the dot is drawn on top of. */
@ViewDebug.ExportedProperty(category = "notification dot")
public Rect iconBounds = new Rect();
diff --git a/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java b/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java
index 513a75d..4aa2846 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java
@@ -16,9 +16,6 @@
package com.android.launcher3.icons;
-import static com.android.launcher3.icons.BaseIconFactory.getBadgeSizeForIconSize;
-import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
-
import android.animation.ObjectAnimator;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -30,30 +27,29 @@ import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.util.FloatProperty;
+import android.util.Property;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import androidx.annotation.Nullable;
-import androidx.core.graphics.ColorUtils;
-public class FastBitmapDrawable extends Drawable implements Drawable.Callback {
+public class FastBitmapDrawable extends Drawable {
private static final Interpolator ACCEL = new AccelerateInterpolator();
private static final Interpolator DEACCEL = new DecelerateInterpolator();
private static final float PRESSED_SCALE = 1.1f;
- public static final int WHITE_SCRIM_ALPHA = 138;
private static final float DISABLED_DESATURATION = 1f;
private static final float DISABLED_BRIGHTNESS = 0.5f;
- protected static final int FULLY_OPAQUE = 255;
public static final int CLICK_FEEDBACK_DURATION = 200;
+ private static ColorFilter sDisabledFColorFilter;
+
protected final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
- protected final Bitmap mBitmap;
+ protected Bitmap mBitmap;
protected final int mIconColor;
@Nullable private ColorFilter mColorFilter;
@@ -63,24 +59,23 @@ public class FastBitmapDrawable extends Drawable implements Drawable.Callback {
float mDisabledAlpha = 1f;
// Animator and properties for the fast bitmap drawable's scale
- private static final FloatProperty<FastBitmapDrawable> SCALE
- = new FloatProperty<FastBitmapDrawable>("scale") {
+ private static final Property<FastBitmapDrawable, Float> SCALE
+ = new Property<FastBitmapDrawable, Float>(Float.TYPE, "scale") {
@Override
public Float get(FastBitmapDrawable fastBitmapDrawable) {
return fastBitmapDrawable.mScale;
}
@Override
- public void setValue(FastBitmapDrawable fastBitmapDrawable, float value) {
+ public void set(FastBitmapDrawable fastBitmapDrawable, Float value) {
fastBitmapDrawable.mScale = value;
fastBitmapDrawable.invalidateSelf();
}
};
private ObjectAnimator mScaleAnimation;
private float mScale = 1;
- private int mAlpha = 255;
- private Drawable mBadge;
+ private int mAlpha = 255;
public FastBitmapDrawable(Bitmap b) {
this(b, Color.TRANSPARENT);
@@ -91,21 +86,14 @@ public class FastBitmapDrawable extends Drawable implements Drawable.Callback {
}
protected FastBitmapDrawable(Bitmap b, int iconColor) {
+ this(b, iconColor, false);
+ }
+
+ protected FastBitmapDrawable(Bitmap b, int iconColor, boolean isDisabled) {
mBitmap = b;
mIconColor = iconColor;
setFilterBitmap(true);
- }
-
- @Override
- protected void onBoundsChange(Rect bounds) {
- super.onBoundsChange(bounds);
- updateBadgeBounds(bounds);
- }
-
- private void updateBadgeBounds(Rect bounds) {
- if (mBadge != null) {
- setBadgeBounds(mBadge, bounds);
- }
+ setIsDisabled(isDisabled);
}
@Override
@@ -115,15 +103,9 @@ public class FastBitmapDrawable extends Drawable implements Drawable.Callback {
Rect bounds = getBounds();
canvas.scale(mScale, mScale, bounds.exactCenterX(), bounds.exactCenterY());
drawInternal(canvas, bounds);
- if (mBadge != null) {
- mBadge.draw(canvas);
- }
canvas.restoreToCount(count);
} else {
drawInternal(canvas, getBounds());
- if (mBadge != null) {
- mBadge.draw(canvas);
- }
}
}
@@ -132,11 +114,10 @@ public class FastBitmapDrawable extends Drawable implements Drawable.Callback {
}
/**
- * Returns the primary icon color, slightly tinted white
+ * Returns the primary icon color
*/
public int getIconColor() {
- int whiteScrim = setColorAlphaBound(Color.WHITE, WHITE_SCRIM_ALPHA);
- return ColorUtils.compositeColors(whiteScrim, mIconColor);
+ return mIconColor;
}
/**
@@ -270,48 +251,27 @@ public class FastBitmapDrawable extends Drawable implements Drawable.Callback {
return mIsDisabled;
}
- public void setBadge(Drawable badge) {
- if (mBadge != null) {
- mBadge.setCallback(null);
- }
- mBadge = badge;
- if (mBadge != null) {
- mBadge.setCallback(this);
+ private ColorFilter getDisabledColorFilter() {
+ if (sDisabledFColorFilter == null) {
+ sDisabledFColorFilter = getDisabledFColorFilter(mDisabledAlpha);
}
- updateBadgeBounds(getBounds());
- updateFilter();
+ return sDisabledFColorFilter;
}
/**
* Updates the paint to reflect the current brightness and saturation.
*/
protected void updateFilter() {
- mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter(mDisabledAlpha) : mColorFilter);
- if (mBadge != null) {
- mBadge.setColorFilter(getColorFilter());
- }
+ mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : mColorFilter);
invalidateSelf();
}
- protected FastBitmapConstantState newConstantState() {
- return new FastBitmapConstantState(mBitmap, mIconColor);
- }
-
@Override
- public final ConstantState getConstantState() {
- FastBitmapConstantState cs = newConstantState();
- cs.mIsDisabled = mIsDisabled;
- if (mBadge != null) {
- cs.mBadgeConstantState = mBadge.getConstantState();
- }
- return cs;
+ public ConstantState getConstantState() {
+ return new FastBitmapConstantState(mBitmap, mIconColor, mIsDisabled);
}
- public static ColorFilter getDisabledColorFilter() {
- return getDisabledColorFilter(1);
- }
-
- private static ColorFilter getDisabledColorFilter(float disabledAlpha) {
+ public static ColorFilter getDisabledFColorFilter(float disabledAlpha) {
ColorMatrix tempBrightnessMatrix = new ColorMatrix();
ColorMatrix tempFilterMatrix = new ColorMatrix();
@@ -327,71 +287,23 @@ public class FastBitmapDrawable extends Drawable implements Drawable.Callback {
mat[14] = brightnessI;
mat[18] = disabledAlpha;
tempFilterMatrix.preConcat(tempBrightnessMatrix);
- return new ColorMatrixColorFilter(tempFilterMatrix);
- }
-
- protected static final int getDisabledColor(int color) {
- int component = (Color.red(color) + Color.green(color) + Color.blue(color)) / 3;
- float scale = 1 - DISABLED_BRIGHTNESS;
- int brightnessI = (int) (255 * DISABLED_BRIGHTNESS);
- component = Math.min(Math.round(scale * component + brightnessI), FULLY_OPAQUE);
- return Color.rgb(component, component, component);
- }
-
- /**
- * Sets the bounds for the badge drawable based on the main icon bounds
- */
- public static void setBadgeBounds(Drawable badge, Rect iconBounds) {
- int size = getBadgeSizeForIconSize(iconBounds.width());
- badge.setBounds(iconBounds.right - size, iconBounds.bottom - size,
- iconBounds.right, iconBounds.bottom);
- }
-
- @Override
- public void invalidateDrawable(Drawable who) {
- if (who == mBadge) {
- invalidateSelf();
- }
- }
-
- @Override
- public void scheduleDrawable(Drawable who, Runnable what, long when) {
- if (who == mBadge) {
- scheduleSelf(what, when);
- }
- }
-
- @Override
- public void unscheduleDrawable(Drawable who, Runnable what) {
- unscheduleSelf(what);
+ return new ColorMatrixColorFilter(tempBrightnessMatrix);
}
protected static class FastBitmapConstantState extends ConstantState {
protected final Bitmap mBitmap;
protected final int mIconColor;
+ protected final boolean mIsDisabled;
- // These are initialized later so that subclasses don't need to
- // pass everything in constructor
- protected boolean mIsDisabled;
- private ConstantState mBadgeConstantState;
-
- public FastBitmapConstantState(Bitmap bitmap, int color) {
+ public FastBitmapConstantState(Bitmap bitmap, int color, boolean isDisabled) {
mBitmap = bitmap;
mIconColor = color;
- }
-
- protected FastBitmapDrawable createDrawable() {
- return new FastBitmapDrawable(mBitmap, mIconColor);
+ mIsDisabled = isDisabled;
}
@Override
- public final FastBitmapDrawable newDrawable() {
- FastBitmapDrawable drawable = createDrawable();
- drawable.setIsDisabled(mIsDisabled);
- if (mBadgeConstantState != null) {
- drawable.setBadge(mBadgeConstantState.newDrawable());
- }
- return drawable;
+ public FastBitmapDrawable newDrawable() {
+ return new FastBitmapDrawable(mBitmap, mIconColor, mIsDisabled);
}
@Override
diff --git a/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java b/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
index d699225..de39e79 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
@@ -238,7 +238,7 @@ public class IconNormalizer {
*/
public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds,
@Nullable Path path, @Nullable boolean[] outMaskShape) {
- if (d instanceof AdaptiveIconDrawable) {
+ if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) {
if (mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
mAdaptiveIconScale = normalizeAdaptiveIcon(d, mMaxSize, mAdaptiveIconBounds);
}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java b/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
index 204651c..449c0da 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
@@ -20,9 +20,7 @@ import static android.content.Intent.ACTION_DATE_CHANGED;
import static android.content.Intent.ACTION_TIMEZONE_CHANGED;
import static android.content.Intent.ACTION_TIME_CHANGED;
import static android.content.res.Resources.ID_NULL;
-import static android.graphics.drawable.AdaptiveIconDrawable.getExtraInsetFraction;
-import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -33,11 +31,8 @@ import android.content.pm.LauncherActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.drawable.AdaptiveIconDrawable;
+import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.PatternMatcher;
@@ -45,14 +40,17 @@ import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
-import androidx.annotation.Nullable;
-import androidx.core.os.BuildCompat;
-
+import com.android.launcher3.icons.ThemedIconDrawable.ThemeData;
import com.android.launcher3.util.SafeCloseable;
+import org.xmlpull.v1.XmlPullParser;
+
import java.util.Calendar;
+import java.util.Collections;
+import java.util.Map;
import java.util.function.Supplier;
/**
@@ -64,22 +62,49 @@ public class IconProvider {
private static final int CONFIG_ICON_MASK_RES_ID = Resources.getSystem().getIdentifier(
"config_icon_mask", "string", "android");
+ private static final String TAG_ICON = "icon";
+ private static final String ATTR_PACKAGE = "package";
+ private static final String ATTR_DRAWABLE = "drawable";
+
private static final String TAG = "IconProvider";
private static final boolean DEBUG = false;
- public static final boolean ATLEAST_T = BuildCompat.isAtLeastT();
private static final String ICON_METADATA_KEY_PREFIX = ".dynamic_icons";
private static final String SYSTEM_STATE_SEPARATOR = " ";
+ private static final String THEMED_ICON_MAP_FILE = "grayscale_icon_map";
- protected final Context mContext;
+ private static final Map<String, ThemeData> DISABLED_MAP = Collections.emptyMap();
+
+ private Map<String, ThemeData> mThemedIconMap;
+
+ private final Context mContext;
private final ComponentName mCalendar;
private final ComponentName mClock;
+ static final int ICON_TYPE_DEFAULT = 0;
+ static final int ICON_TYPE_CALENDAR = 1;
+ static final int ICON_TYPE_CLOCK = 2;
+
public IconProvider(Context context) {
+ this(context, false);
+ }
+
+ public IconProvider(Context context, boolean supportsIconTheme) {
mContext = context;
mCalendar = parseComponentOrNull(context, R.string.calendar_component_name);
mClock = parseComponentOrNull(context, R.string.clock_component_name);
+ if (!supportsIconTheme) {
+ // Initialize an empty map if theming is not supported
+ mThemedIconMap = DISABLED_MAP;
+ }
+ }
+
+ /**
+ * Enables or disables icon theme support
+ */
+ public void setIconThemeSupported(boolean isSupported) {
+ mThemedIconMap = isSupported ? null : DISABLED_MAP;
}
/**
@@ -98,7 +123,7 @@ public class IconProvider {
* Loads the icon for the provided LauncherActivityInfo
*/
public Drawable getIcon(LauncherActivityInfo info, int iconDpi) {
- return getIconWithOverrides(info.getApplicationInfo().packageName, iconDpi,
+ return getIconWithOverrides(info.getApplicationInfo().packageName, info.getUser(), iconDpi,
() -> info.getIcon(iconDpi));
}
@@ -113,36 +138,32 @@ public class IconProvider {
* Loads the icon for the provided activity info
*/
public Drawable getIcon(ActivityInfo info, int iconDpi) {
- return getIconWithOverrides(info.applicationInfo.packageName, iconDpi,
- () -> loadActivityInfoIcon(info, iconDpi));
+ return getIconWithOverrides(info.applicationInfo.packageName,
+ UserHandle.getUserHandleForUid(info.applicationInfo.uid),
+ iconDpi, () -> loadActivityInfoIcon(info, iconDpi));
}
- @TargetApi(Build.VERSION_CODES.TIRAMISU)
- private Drawable getIconWithOverrides(String packageName, int iconDpi,
+ private Drawable getIconWithOverrides(String packageName, UserHandle user, int iconDpi,
Supplier<Drawable> fallback) {
- ThemeData td = getThemeDataForPackage(packageName);
-
Drawable icon = null;
+
+ int iconType = ICON_TYPE_DEFAULT;
if (mCalendar != null && mCalendar.getPackageName().equals(packageName)) {
- icon = loadCalendarDrawable(iconDpi, td);
- } else if (mClock != null && mClock.getPackageName().equals(packageName)) {
- icon = ClockDrawableWrapper.forPackage(mContext, mClock.getPackageName(), iconDpi, td);
+ icon = loadCalendarDrawable(iconDpi);
+ iconType = ICON_TYPE_CALENDAR;
+ } else if (mClock != null
+ && mClock.getPackageName().equals(packageName)
+ && Process.myUserHandle().equals(user)) {
+ icon = loadClockDrawable(iconDpi);
+ iconType = ICON_TYPE_CLOCK;
}
if (icon == null) {
icon = fallback.get();
- if (ATLEAST_T && icon instanceof AdaptiveIconDrawable && td != null) {
- AdaptiveIconDrawable aid = (AdaptiveIconDrawable) icon;
- if (aid.getMonochrome() == null) {
- icon = new AdaptiveIconDrawable(aid.getBackground(),
- aid.getForeground(), td.loadPaddedDrawable());
- }
- }
+ iconType = ICON_TYPE_DEFAULT;
}
- return icon;
- }
- protected ThemeData getThemeDataForPackage(String packageName) {
- return null;
+ ThemeData td = getThemedIconMap().get(packageName);
+ return td != null ? td.wrapDrawable(icon, iconType) : icon;
}
private Drawable loadActivityInfoIcon(ActivityInfo ai, int density) {
@@ -163,8 +184,45 @@ public class IconProvider {
return icon;
}
- @TargetApi(Build.VERSION_CODES.TIRAMISU)
- private Drawable loadCalendarDrawable(int iconDpi, @Nullable ThemeData td) {
+ private Map<String, ThemeData> getThemedIconMap() {
+ if (mThemedIconMap != null) {
+ return mThemedIconMap;
+ }
+ ArrayMap<String, ThemeData> map = new ArrayMap<>();
+ try {
+ Resources res = mContext.getResources();
+ int resID = res.getIdentifier(THEMED_ICON_MAP_FILE, "xml", mContext.getPackageName());
+ if (resID != 0) {
+ XmlResourceParser parser = res.getXml(resID);
+ final int depth = parser.getDepth();
+
+ int type;
+
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT);
+
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ if (TAG_ICON.equals(parser.getName())) {
+ String pkg = parser.getAttributeValue(null, ATTR_PACKAGE);
+ int iconId = parser.getAttributeResourceValue(null, ATTR_DRAWABLE, 0);
+ if (iconId != 0 && !TextUtils.isEmpty(pkg)) {
+ map.put(pkg, new ThemeData(res, iconId));
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to parse icon map", e);
+ }
+ mThemedIconMap = map;
+ return mThemedIconMap;
+ }
+
+ private Drawable loadCalendarDrawable(int iconDpi) {
PackageManager pm = mContext.getPackageManager();
try {
final Bundle metadata = pm.getActivityInfo(
@@ -175,22 +233,7 @@ public class IconProvider {
final int id = getDynamicIconId(metadata, resources);
if (id != ID_NULL) {
if (DEBUG) Log.d(TAG, "Got icon #" + id);
- Drawable drawable = resources.getDrawableForDensity(id, iconDpi, null /* theme */);
- if (ATLEAST_T && drawable instanceof AdaptiveIconDrawable && td != null) {
- AdaptiveIconDrawable aid = (AdaptiveIconDrawable) drawable;
- if (aid.getMonochrome() != null) {
- return drawable;
- }
- if ("array".equals(td.mResources.getResourceTypeName(td.mResID))) {
- TypedArray ta = td.mResources.obtainTypedArray(td.mResID);
- int monoId = ta.getResourceId(IconProvider.getDay(), ID_NULL);
- ta.recycle();
- return monoId == ID_NULL ? drawable
- : new AdaptiveIconDrawable(aid.getBackground(), aid.getForeground(),
- new ThemeData(td.mResources, monoId).loadPaddedDrawable());
- }
- }
- return drawable;
+ return resources.getDrawableForDensity(id, iconDpi, null /* theme */);
}
} catch (PackageManager.NameNotFoundException e) {
if (DEBUG) {
@@ -201,6 +244,10 @@ public class IconProvider {
return null;
}
+ private Drawable loadClockDrawable(int iconDpi) {
+ return ClockDrawableWrapper.forPackage(mContext, mClock.getPackageName(), iconDpi);
+ }
+
/**
* @param metadata metadata of the default activity of Calendar
* @param resources from the Calendar package
@@ -228,7 +275,7 @@ public class IconProvider {
/**
* @return Today's day of the month, zero-indexed.
*/
- private static int getDay() {
+ static int getDay() {
return Calendar.getInstance().get(Calendar.DAY_OF_MONTH) - 1;
}
@@ -242,7 +289,8 @@ public class IconProvider {
*/
public String getSystemIconState() {
return (CONFIG_ICON_MASK_RES_ID == ID_NULL
- ? "" : mContext.getResources().getString(CONFIG_ICON_MASK_RES_ID));
+ ? "" : mContext.getResources().getString(CONFIG_ICON_MASK_RES_ID))
+ + (mThemedIconMap == DISABLED_MAP ? ",no-theme" : ",with-theme");
}
/**
@@ -252,28 +300,6 @@ public class IconProvider {
return new IconChangeReceiver(listener, handler);
}
- public static class ThemeData {
-
- final Resources mResources;
- final int mResID;
-
- public ThemeData(Resources resources, int resID) {
- mResources = resources;
- mResID = resID;
- }
-
- Drawable loadPaddedDrawable() {
- if (!"drawable".equals(mResources.getResourceTypeName(mResID))) {
- return null;
- }
- Drawable d = mResources.getDrawable(mResID).mutate();
- d = new InsetDrawable(d, .2f);
- float inset = getExtraInsetFraction() / (1 + 2 * getExtraInsetFraction());
- Drawable fg = new InsetDrawable(d, inset);
- return fg;
- }
- }
-
private class IconChangeReceiver extends BroadcastReceiver implements SafeCloseable {
private final IconChangeListener mCallback;
diff --git a/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java b/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java
index 96dee3b..e24f353 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java
@@ -35,14 +35,14 @@ public class ShadowGenerator {
public static final boolean ENABLE_SHADOWS = true;
- public static final float BLUR_FACTOR = 1.68f/48;
+ public static final float BLUR_FACTOR = 1.5f/48;
// Percent of actual icon size
public static final float KEY_SHADOW_DISTANCE = 1f/48;
- private static final int KEY_SHADOW_ALPHA = 7;
+ private static final int KEY_SHADOW_ALPHA = 10;
// Percent of actual icon size
private static final float HALF_DISTANCE = 0.5f;
- private static final int AMBIENT_SHADOW_ALPHA = 25;
+ private static final int AMBIENT_SHADOW_ALPHA = 7;
private final int mIconSize;
diff --git a/iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.java b/iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.java
index 494d657..b2e554b 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.java
@@ -17,16 +17,37 @@ package com.android.launcher3.icons;
import static android.content.res.Configuration.UI_MODE_NIGHT_MASK;
import static android.content.res.Configuration.UI_MODE_NIGHT_YES;
+import static android.content.res.Resources.ID_NULL;
+
+import static com.android.launcher3.icons.GraphicsUtils.getExpectedBitmapSize;
+import static com.android.launcher3.icons.IconProvider.ICON_TYPE_CALENDAR;
+import static com.android.launcher3.icons.IconProvider.ICON_TYPE_CLOCK;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.BlendMode;
-import android.graphics.BlendModeColorFilter;
+import android.graphics.BitmapFactory;
import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.icons.BitmapInfo.Extender;
+import com.android.launcher3.icons.cache.BaseIconCache;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
/**
* Class to handle monochrome themed app icons
@@ -36,50 +57,46 @@ public class ThemedIconDrawable extends FastBitmapDrawable {
public static final String TAG = "ThemedIconDrawable";
- final BitmapInfo bitmapInfo;
+ final ThemedBitmapInfo bitmapInfo;
final int colorFg, colorBg;
// The foreground/monochrome icon for the app
- private final Bitmap mMonoIcon;
- private final Paint mMonoPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
-
- private final Bitmap mBgBitmap;
- private final Paint mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
-
- private final ColorFilter mBgFilter, mMonoFilter;
+ private final Drawable mMonochromeIcon;
+ private final AdaptiveIconDrawable mBgWrapper;
+ private final Rect mBadgeBounds;
protected ThemedIconDrawable(ThemedConstantState constantState) {
- super(constantState.mBitmap, constantState.colorFg);
+ super(constantState.mBitmap, constantState.colorFg, constantState.mIsDisabled);
bitmapInfo = constantState.bitmapInfo;
colorBg = constantState.colorBg;
colorFg = constantState.colorFg;
- mMonoIcon = bitmapInfo.mMono;
- mMonoFilter = new BlendModeColorFilter(colorFg, BlendMode.SRC_IN);
- mMonoPaint.setColorFilter(mMonoFilter);
+ mMonochromeIcon = bitmapInfo.mThemeData.loadMonochromeDrawable(colorFg);
+ mBgWrapper = new AdaptiveIconDrawable(new ColorDrawable(colorBg), null);
+ mBadgeBounds = bitmapInfo.mUserBadge == null ? null :
+ new Rect(0, 0, bitmapInfo.mUserBadge.getWidth(), bitmapInfo.mUserBadge.getHeight());
- mBgBitmap = bitmapInfo.mWhiteShadowLayer;
- mBgFilter = new BlendModeColorFilter(colorBg, BlendMode.SRC_IN);
- mBgPaint.setColorFilter(mBgFilter);
}
@Override
- protected void drawInternal(Canvas canvas, Rect bounds) {
- canvas.drawBitmap(mBgBitmap, null, bounds, mBgPaint);
- canvas.drawBitmap(mMonoIcon, null, bounds, mMonoPaint);
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ mBgWrapper.setBounds(bounds);
+ mMonochromeIcon.setBounds(bounds);
}
@Override
- protected void updateFilter() {
- super.updateFilter();
- int alpha = mIsDisabled ? (int) (mDisabledAlpha * FULLY_OPAQUE) : FULLY_OPAQUE;
- mBgPaint.setAlpha(alpha);
- mBgPaint.setColorFilter(mIsDisabled ? new BlendModeColorFilter(
- getDisabledColor(colorBg), BlendMode.SRC_IN) : mBgFilter);
-
- mMonoPaint.setAlpha(alpha);
- mMonoPaint.setColorFilter(mIsDisabled ? new BlendModeColorFilter(
- getDisabledColor(colorFg), BlendMode.SRC_IN) : mMonoFilter);
+ protected void drawInternal(Canvas canvas, Rect bounds) {
+ int count = canvas.save();
+ canvas.scale(bitmapInfo.mNormalizationScale, bitmapInfo.mNormalizationScale,
+ bounds.exactCenterX(), bounds.exactCenterY());
+ mPaint.setColor(colorBg);
+ canvas.drawPath(mBgWrapper.getIconMask(), mPaint);
+ mMonochromeIcon.draw(canvas);
+ canvas.restoreToCount(count);
+ if (mBadgeBounds != null) {
+ canvas.drawBitmap(bitmapInfo.mUserBadge, mBadgeBounds, getBounds(), mPaint);
+ }
}
@Override
@@ -88,35 +105,177 @@ public class ThemedIconDrawable extends FastBitmapDrawable {
}
@Override
- public FastBitmapConstantState newConstantState() {
- return new ThemedConstantState(bitmapInfo, colorBg, colorFg);
- }
-
- public void changeBackgroundColor(int colorBg){
- mBgPaint.setColorFilter(new BlendModeColorFilter(colorBg, BlendMode.SRC_IN));
+ public ConstantState getConstantState() {
+ return new ThemedConstantState(bitmapInfo, colorBg, colorFg, mIsDisabled);
}
static class ThemedConstantState extends FastBitmapConstantState {
- final BitmapInfo bitmapInfo;
+ final ThemedBitmapInfo bitmapInfo;
final int colorFg, colorBg;
- public ThemedConstantState(BitmapInfo bitmapInfo, int colorBg, int colorFg) {
- super(bitmapInfo.icon, bitmapInfo.color);
+ public ThemedConstantState(ThemedBitmapInfo bitmapInfo,
+ int colorBg, int colorFg, boolean isDisabled) {
+ super(bitmapInfo.icon, bitmapInfo.color, isDisabled);
this.bitmapInfo = bitmapInfo;
this.colorBg = colorBg;
this.colorFg = colorFg;
}
@Override
- public FastBitmapDrawable createDrawable() {
+ public FastBitmapDrawable newDrawable() {
return new ThemedIconDrawable(this);
}
}
- public static FastBitmapDrawable newDrawable(BitmapInfo info, Context context) {
- int[] colors = getColors(context);
- return new ThemedConstantState(info, colors[0], colors[1]).newDrawable();
+ public static class ThemedBitmapInfo extends BitmapInfo {
+
+ final ThemeData mThemeData;
+ final float mNormalizationScale;
+ final Bitmap mUserBadge;
+
+ public ThemedBitmapInfo(Bitmap icon, int color, ThemeData themeData,
+ float normalizationScale, Bitmap userBadge) {
+ super(icon, color);
+ mThemeData = themeData;
+ mNormalizationScale = normalizationScale;
+ mUserBadge = userBadge;
+ }
+
+ @Override
+ public FastBitmapDrawable newThemedIcon(Context context) {
+ int[] colors = getColors(context);
+ FastBitmapDrawable drawable = new ThemedConstantState(this, colors[0], colors[1], false)
+ .newDrawable();
+ drawable.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f);
+ return drawable;
+ }
+
+ @Nullable
+ public byte[] toByteArray() {
+ if (isNullOrLowRes()) {
+ return null;
+ }
+ String resName = mThemeData.mResources.getResourceName(mThemeData.mResID);
+ ByteArrayOutputStream out = new ByteArrayOutputStream(
+ getExpectedBitmapSize(icon) + 3 + resName.length());
+ try {
+ DataOutputStream dos = new DataOutputStream(out);
+ dos.writeByte(TYPE_THEMED);
+ dos.writeFloat(mNormalizationScale);
+ dos.writeUTF(resName);
+ icon.compress(Bitmap.CompressFormat.PNG, 100, dos);
+
+ dos.flush();
+ dos.close();
+ return out.toByteArray();
+ } catch (IOException e) {
+ Log.w(TAG, "Could not write bitmap");
+ return null;
+ }
+ }
+
+ static ThemedBitmapInfo decode(byte[] data, int color,
+ BitmapFactory.Options decodeOptions, UserHandle user, BaseIconCache iconCache,
+ Context context) {
+ try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data))) {
+ dis.readByte(); // type
+ float normalizationScale = dis.readFloat();
+
+ String resName = dis.readUTF();
+ int resId = context.getResources()
+ .getIdentifier(resName, "drawable", context.getPackageName());
+ if (resId == ID_NULL) {
+ return null;
+ }
+
+ Bitmap userBadgeBitmap = null;
+ if (!Process.myUserHandle().equals(user)) {
+ try (BaseIconFactory iconFactory = iconCache.getIconFactory()) {
+ userBadgeBitmap = iconFactory.getUserBadgeBitmap(user);
+ }
+ }
+
+ ThemeData themeData = new ThemeData(context.getResources(), resId);
+ Bitmap icon = BitmapFactory.decodeStream(dis, null, decodeOptions);
+ return new ThemedBitmapInfo(icon, color, themeData, normalizationScale,
+ userBadgeBitmap);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+ }
+
+ public static class ThemeData {
+
+ final Resources mResources;
+ final int mResID;
+
+ public ThemeData(Resources resources, int resID) {
+ mResources = resources;
+ mResID = resID;
+ }
+
+ Drawable loadMonochromeDrawable(int accentColor) {
+ Drawable d = mResources.getDrawable(mResID).mutate();
+ d.setTint(accentColor);
+ d = new InsetDrawable(d, .2f);
+ return d;
+ }
+
+ public Drawable wrapDrawable(Drawable original, int iconType) {
+ if (!(original instanceof AdaptiveIconDrawable)) {
+ return original;
+ }
+ AdaptiveIconDrawable aid = (AdaptiveIconDrawable) original;
+ String resourceType = mResources.getResourceTypeName(mResID);
+ if (iconType == ICON_TYPE_CALENDAR && "array".equals(resourceType)) {
+ TypedArray ta = mResources.obtainTypedArray(mResID);
+ int id = ta.getResourceId(IconProvider.getDay(), ID_NULL);
+ ta.recycle();
+ return id == ID_NULL ? original
+ : new ThemedAdaptiveIcon(aid, new ThemeData(mResources, id));
+ } else if (iconType == ICON_TYPE_CLOCK && "array".equals(resourceType)) {
+ ((ClockDrawableWrapper) original).mThemeData = this;
+ return original;
+ } else if ("drawable".equals(resourceType)) {
+ return new ThemedAdaptiveIcon(aid, this);
+ } else {
+ return original;
+ }
+ }
+ }
+
+ static class ThemedAdaptiveIcon extends AdaptiveIconDrawable implements Extender {
+
+ protected final ThemeData mThemeData;
+
+ public ThemedAdaptiveIcon(AdaptiveIconDrawable parent, ThemeData themeData) {
+ super(parent.getBackground(), parent.getForeground());
+ mThemeData = themeData;
+ }
+
+ @Override
+ public BitmapInfo getExtendedInfo(Bitmap bitmap, int color, BaseIconFactory iconFactory,
+ float normalizationScale, UserHandle user) {
+ Bitmap userBadge = Process.myUserHandle().equals(user)
+ ? null : iconFactory.getUserBadgeBitmap(user);
+ return new ThemedBitmapInfo(bitmap, color, mThemeData, normalizationScale, userBadge);
+ }
+
+ @Override
+ public void drawForPersistence(Canvas canvas) {
+ draw(canvas);
+ }
+
+ @Override
+ public Drawable getThemedDrawable(Context context) {
+ int[] colors = getColors(context);
+ Drawable bg = new ColorDrawable(colors[0]);
+ float inset = getExtraInsetFraction() / (1 + 2 * getExtraInsetFraction());
+ Drawable fg = new InsetDrawable(mThemeData.loadMonochromeDrawable(colors[1]), inset);
+ return new AdaptiveIconDrawable(bg, fg);
+ }
}
/**
@@ -134,9 +293,4 @@ public class ThemedIconDrawable extends FastBitmapDrawable {
}
return colors;
}
-
- @Override
- public int getIconColor() {
- return colorFg;
- }
}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
index 057bdc2..d685737 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
@@ -15,15 +15,10 @@
*/
package com.android.launcher3.icons.cache;
-import static android.graphics.BitmapFactory.decodeByteArray;
-
import static com.android.launcher3.icons.BaseIconFactory.getFullResDefaultActivityIcon;
import static com.android.launcher3.icons.BitmapInfo.LOW_RES_ICON;
-import static com.android.launcher3.icons.GraphicsUtils.flattenBitmap;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
-import static java.util.Objects.requireNonNull;
-
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
@@ -37,34 +32,26 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.LocaleList;
import android.os.Looper;
import android.os.Process;
-import android.os.Trace;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
-import android.util.SparseArray;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.icons.BaseIconFactory;
-import com.android.launcher3.icons.BaseIconFactory.IconOptions;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.SQLiteCacheHelper;
-import java.nio.ByteBuffer;
import java.util.AbstractMap;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -90,6 +77,8 @@ public abstract class BaseIconCache {
public CharSequence contentDescription = "";
}
+ private final HashMap<UserHandle, BitmapInfo> mDefaultIcons = new HashMap<>();
+
protected final Context mContext;
protected final PackageManager mPackageManager;
@@ -101,9 +90,6 @@ public abstract class BaseIconCache {
protected LocaleList mLocaleList = LocaleList.getEmptyLocaleList();
protected String mSystemState = "";
- private BitmapInfo mDefaultIcon;
- private final SparseArray<FlagOp> mUserFlagOpMap = new SparseArray<>();
-
private final String mDbFileName;
private final Looper mBgLooper;
@@ -159,8 +145,7 @@ public abstract class BaseIconCache {
private synchronized void updateIconParamsBg(int iconDpi, int iconPixelSize) {
mIconDpi = iconDpi;
- mDefaultIcon = null;
- mUserFlagOpMap.clear();
+ mDefaultIcons.clear();
mIconDb.clear();
mIconDb.close();
mIconDb = new IconDB(mContext, mDbFileName, iconPixelSize);
@@ -191,6 +176,12 @@ public abstract class BaseIconCache {
return getFullResDefaultActivityIcon(mIconDpi);
}
+ private BitmapInfo makeDefaultIcon(UserHandle user) {
+ try (BaseIconFactory li = getIconFactory()) {
+ return li.makeDefaultIcon(user);
+ }
+ }
+
/**
* Remove any records for the supplied ComponentName.
*/
@@ -273,13 +264,7 @@ public abstract class BaseIconCache {
// (e.g. fallback icon, default icon). So we drop here since there's no point in caching
// an empty entry.
if (entry.bitmap.isNullOrLowRes()) return;
-
- CharSequence entryTitle = cachingLogic.getLabel(object);
- if (entryTitle == null) {
- Log.d(TAG, "No label returned from caching logic instance: " + cachingLogic);
- }
- entry.title = entryTitle;
-
+ entry.title = cachingLogic.getLabel(object);
entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user);
if (cachingLogic.addToMemCache()) mCache.put(key, entry);
@@ -303,26 +288,10 @@ public abstract class BaseIconCache {
}
public synchronized BitmapInfo getDefaultIcon(UserHandle user) {
- if (mDefaultIcon == null) {
- try (BaseIconFactory li = getIconFactory()) {
- mDefaultIcon = li.makeDefaultIcon();
- }
- }
- return mDefaultIcon.withFlags(getUserFlagOpLocked(user));
- }
-
- protected FlagOp getUserFlagOpLocked(UserHandle user) {
- int key = user.hashCode();
- int index;
- if ((index = mUserFlagOpMap.indexOfKey(key)) >= 0) {
- return mUserFlagOpMap.valueAt(index);
- } else {
- try (BaseIconFactory li = getIconFactory()) {
- FlagOp op = li.getBitmapFlagOp(new IconOptions().setUser(user));
- mUserFlagOpMap.put(key, op);
- return op;
- }
+ if (!mDefaultIcons.containsKey(user)) {
+ mDefaultIcons.put(user, makeDefaultIcon(user));
}
+ return mDefaultIcons.get(user);
}
public boolean isDefaultIcon(BitmapInfo icon, UserHandle user) {
@@ -337,20 +306,6 @@ public abstract class BaseIconCache {
@NonNull ComponentName componentName, @NonNull UserHandle user,
@NonNull Supplier<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
boolean usePackageIcon, boolean useLowResIcon) {
- return cacheLocked(
- componentName,
- user,
- infoProvider,
- cachingLogic,
- null,
- usePackageIcon,
- useLowResIcon);
- }
-
- protected <T> CacheEntry cacheLocked(
- @NonNull ComponentName componentName, @NonNull UserHandle user,
- @NonNull Supplier<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
- @Nullable Cursor cursor, boolean usePackageIcon, boolean useLowResIcon) {
assertWorkerThread();
ComponentKey cacheKey = new ComponentKey(componentName, user);
CacheEntry entry = mCache.get(cacheKey);
@@ -363,21 +318,31 @@ public abstract class BaseIconCache {
// Check the DB first.
T object = null;
boolean providerFetchedOnce = false;
- boolean cacheEntryUpdated = cursor == null
- ? getEntryFromDBLocked(cacheKey, entry, useLowResIcon)
- : updateTitleAndIconLocked(cacheKey, entry, cursor, useLowResIcon);
- if (!cacheEntryUpdated) {
+
+ if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
object = infoProvider.get();
providerFetchedOnce = true;
- loadFallbackIcon(
- object,
- entry,
- cachingLogic,
- usePackageIcon,
- /* usePackageTitle= */ true,
- componentName,
- user);
+ if (object != null) {
+ entry.bitmap = cachingLogic.loadIcon(mContext, object);
+ } else {
+ if (usePackageIcon) {
+ CacheEntry packageEntry = getEntryForPackageLocked(
+ componentName.getPackageName(), user, false);
+ if (packageEntry != null) {
+ if (DEBUG) Log.d(TAG, "using package default icon for " +
+ componentName.toShortString());
+ entry.bitmap = packageEntry.bitmap;
+ entry.title = packageEntry.title;
+ entry.contentDescription = packageEntry.contentDescription;
+ }
+ }
+ if (entry.bitmap == null) {
+ if (DEBUG) Log.d(TAG, "using default icon for " +
+ componentName.toShortString());
+ entry.bitmap = getDefaultIcon(user);
+ }
+ }
}
if (TextUtils.isEmpty(entry.title)) {
@@ -386,56 +351,15 @@ public abstract class BaseIconCache {
providerFetchedOnce = true;
}
if (object != null) {
- loadFallbackTitle(object, entry, cachingLogic, user);
+ entry.title = cachingLogic.getLabel(object);
+ entry.contentDescription = mPackageManager.getUserBadgedLabel(
+ cachingLogic.getDescription(object, entry.title), user);
}
}
}
return entry;
}
- /**
- * Fallback method for loading an icon bitmap.
- */
- protected <T> void loadFallbackIcon(
- T object, CacheEntry entry, @NonNull CachingLogic<T> cachingLogic,
- boolean usePackageIcon, boolean usePackageTitle, @NonNull ComponentName componentName,
- @NonNull UserHandle user) {
- if (object != null) {
- entry.bitmap = cachingLogic.loadIcon(mContext, object);
- } else {
- if (usePackageIcon) {
- CacheEntry packageEntry = getEntryForPackageLocked(
- componentName.getPackageName(), user, false);
- if (packageEntry != null) {
- if (DEBUG) Log.d(TAG, "using package default icon for " +
- componentName.toShortString());
- entry.bitmap = packageEntry.bitmap;
- entry.contentDescription = packageEntry.contentDescription;
-
- if (usePackageTitle) {
- entry.title = packageEntry.title;
- }
- }
- }
- if (entry.bitmap == null) {
- if (DEBUG) Log.d(TAG, "using default icon for " +
- componentName.toShortString());
- entry.bitmap = getDefaultIcon(user);
- }
- }
- }
-
- /**
- * Fallback method for loading an app title.
- */
- protected <T> void loadFallbackTitle(
- T object, CacheEntry entry, @NonNull CachingLogic<T> cachingLogic,
- @NonNull UserHandle user) {
- entry.title = cachingLogic.getLabel(object);
- entry.contentDescription = mPackageManager.getUserBadgedLabel(
- cachingLogic.getDescription(object, entry.title), user);
- }
-
public synchronized void clear() {
assertWorkerThread();
mIconDb.clear();
@@ -461,7 +385,7 @@ public abstract class BaseIconCache {
}
if (icon != null) {
BaseIconFactory li = getIconFactory();
- entry.bitmap = li.createShapedIconBitmap(icon, new IconOptions().setUser(user));
+ entry.bitmap = li.createShapedIconBitmap(icon, user);
li.close();
}
if (!TextUtils.isEmpty(title) && entry.bitmap.icon != null) {
@@ -489,7 +413,7 @@ public abstract class BaseIconCache {
boolean entryUpdated = true;
// Check the DB first.
- if (!getEntryFromDBLocked(cacheKey, entry, useLowResIcon)) {
+ if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
try {
int flags = Process.myUserHandle().equals(user) ? 0 :
PackageManager.GET_UNINSTALLED_PACKAGES;
@@ -503,8 +427,8 @@ public abstract class BaseIconCache {
// Load the full res icon for the application, but if useLowResIcon is set, then
// only keep the low resolution icon instead of the larger full-sized icon
BitmapInfo iconInfo = li.createBadgedIconBitmap(
- appInfo.loadIcon(mPackageManager),
- new IconOptions().setUser(user).setInstantApp(isInstantApp(appInfo)));
+ appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion,
+ isInstantApp(appInfo));
li.close();
entry.title = appInfo.loadLabel(mPackageManager);
@@ -533,10 +457,8 @@ public abstract class BaseIconCache {
return entry;
}
- protected boolean getEntryFromDBLocked(
- ComponentKey cacheKey, CacheEntry entry, boolean lowRes) {
+ protected boolean getEntryFromDB(ComponentKey cacheKey, CacheEntry entry, boolean lowRes) {
Cursor c = null;
- Trace.beginSection("loadIconIndividually");
try {
c = mIconDb.query(
lowRes ? IconDB.COLUMNS_LOW_RES : IconDB.COLUMNS_HIGH_RES,
@@ -545,7 +467,26 @@ public abstract class BaseIconCache {
cacheKey.componentName.flattenToString(),
Long.toString(getSerialNumberForUser(cacheKey.user))});
if (c.moveToNext()) {
- return updateTitleAndIconLocked(cacheKey, entry, c, lowRes);
+ // Set the alpha to be 255, so that we never have a wrong color
+ entry.bitmap = BitmapInfo.of(LOW_RES_ICON, setColorAlphaBound(c.getInt(0), 255));
+ entry.title = c.getString(1);
+ if (entry.title == null) {
+ entry.title = "";
+ entry.contentDescription = "";
+ } else {
+ entry.contentDescription = mPackageManager.getUserBadgedLabel(
+ entry.title, cacheKey.user);
+ }
+
+ if (!lowRes) {
+ try {
+ entry.bitmap = BitmapInfo.fromByteArray(
+ c.getBlob(2), entry.bitmap.color, cacheKey.user, this, mContext);
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ return entry.bitmap != null;
}
} catch (SQLiteException e) {
Log.d(TAG, "Error reading icon cache", e);
@@ -553,62 +494,10 @@ public abstract class BaseIconCache {
if (c != null) {
c.close();
}
- Trace.endSection();
}
return false;
}
- private boolean updateTitleAndIconLocked(
- ComponentKey cacheKey, CacheEntry entry, Cursor c, boolean lowRes) {
- // Set the alpha to be 255, so that we never have a wrong color
- entry.bitmap = BitmapInfo.of(LOW_RES_ICON,
- setColorAlphaBound(c.getInt(IconDB.INDEX_COLOR), 255));
- entry.title = c.getString(IconDB.INDEX_TITLE);
- if (entry.title == null) {
- entry.title = "";
- entry.contentDescription = "";
- } else {
- entry.contentDescription = mPackageManager.getUserBadgedLabel(
- entry.title, cacheKey.user);
- }
-
- if (!lowRes) {
- byte[] data = c.getBlob(IconDB.INDEX_ICON);
- if (data == null) {
- return false;
- }
- try {
- BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
- decodeOptions.inPreferredConfig = Config.HARDWARE;
- entry.bitmap = BitmapInfo.of(
- requireNonNull(decodeByteArray(data, 0, data.length, decodeOptions)),
- entry.bitmap.color);
- } catch (Exception e) {
- return false;
- }
-
- // Decode mono bitmap
- data = c.getBlob(IconDB.INDEX_MONO_ICON);
- Bitmap icon = entry.bitmap.icon;
- if (data != null && data.length == icon.getHeight() * icon.getWidth()) {
- Bitmap monoBitmap = Bitmap.createBitmap(
- icon.getWidth(), icon.getHeight(), Config.ALPHA_8);
- monoBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(data));
- Bitmap hwMonoBitmap = monoBitmap.copy(Config.HARDWARE, false /*isMutable*/);
- if (hwMonoBitmap != null) {
- monoBitmap.recycle();
- monoBitmap = hwMonoBitmap;
- }
- try (BaseIconFactory factory = getIconFactory()) {
- entry.bitmap.setMonoIcon(monoBitmap, factory);
- }
- }
- }
- entry.bitmap.flags = c.getInt(IconDB.INDEX_FLAGS);
- entry.bitmap = entry.bitmap.withFlags(getUserFlagOpLocked(cacheKey.user));
- return entry.bitmap != null;
- }
-
/**
* Returns a cursor for an arbitrary query to the cache db
*/
@@ -621,7 +510,7 @@ public abstract class BaseIconCache {
* Cache class to store the actual entries on disk
*/
public static final class IconDB extends SQLiteCacheHelper {
- private static final int RELEASE_VERSION = 34;
+ private static final int RELEASE_VERSION = 31;
public static final String TABLE_NAME = "icons";
public static final String COLUMN_ROWID = "rowid";
@@ -631,29 +520,14 @@ public abstract class BaseIconCache {
public static final String COLUMN_VERSION = "version";
public static final String COLUMN_ICON = "icon";
public static final String COLUMN_ICON_COLOR = "icon_color";
- public static final String COLUMN_MONO_ICON = "mono_icon";
- public static final String COLUMN_FLAGS = "flags";
public static final String COLUMN_LABEL = "label";
public static final String COLUMN_SYSTEM_STATE = "system_state";
public static final String COLUMN_KEYWORDS = "keywords";
+ public static final String[] COLUMNS_HIGH_RES = new String[] {
+ IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL, IconDB.COLUMN_ICON };
public static final String[] COLUMNS_LOW_RES = new String[] {
- COLUMN_COMPONENT,
- COLUMN_LABEL,
- COLUMN_ICON_COLOR,
- COLUMN_FLAGS};
- public static final String[] COLUMNS_HIGH_RES = Arrays.copyOf(COLUMNS_LOW_RES,
- COLUMNS_LOW_RES.length + 2, String[].class);
- static {
- COLUMNS_HIGH_RES[COLUMNS_LOW_RES.length] = COLUMN_ICON;
- COLUMNS_HIGH_RES[COLUMNS_LOW_RES.length + 1] = COLUMN_MONO_ICON;
- }
- private static final int INDEX_TITLE = Arrays.asList(COLUMNS_LOW_RES).indexOf(COLUMN_LABEL);
- private static final int INDEX_COLOR = Arrays.asList(COLUMNS_LOW_RES)
- .indexOf(COLUMN_ICON_COLOR);
- private static final int INDEX_FLAGS = Arrays.asList(COLUMNS_LOW_RES).indexOf(COLUMN_FLAGS);
- private static final int INDEX_ICON = COLUMNS_LOW_RES.length;
- private static final int INDEX_MONO_ICON = INDEX_ICON + 1;
+ IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL };
public IconDB(Context context, String dbFileName, int iconPixelSize) {
super(context, dbFileName, (RELEASE_VERSION << 16) + iconPixelSize, TABLE_NAME);
@@ -667,9 +541,7 @@ public abstract class BaseIconCache {
+ COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, "
+ COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, "
+ COLUMN_ICON + " BLOB, "
- + COLUMN_MONO_ICON + " BLOB, "
+ COLUMN_ICON_COLOR + " INTEGER NOT NULL DEFAULT 0, "
- + COLUMN_FLAGS + " INTEGER NOT NULL DEFAULT 0, "
+ COLUMN_LABEL + " TEXT, "
+ COLUMN_SYSTEM_STATE + " TEXT, "
+ COLUMN_KEYWORDS + " TEXT, "
@@ -681,26 +553,8 @@ public abstract class BaseIconCache {
private ContentValues newContentValues(BitmapInfo bitmapInfo, String label,
String packageName, @Nullable String keywords) {
ContentValues values = new ContentValues();
- if (bitmapInfo.canPersist()) {
- values.put(IconDB.COLUMN_ICON, flattenBitmap(bitmapInfo.icon));
-
- // Persist mono bitmap as alpha channel
- Bitmap mono = bitmapInfo.getMono();
- if (mono != null && mono.getHeight() == bitmapInfo.icon.getHeight()
- && mono.getWidth() == bitmapInfo.icon.getWidth()
- && mono.getConfig() == Config.ALPHA_8) {
- byte[] pixels = new byte[mono.getWidth() * mono.getHeight()];
- mono.copyPixelsToBuffer(ByteBuffer.wrap(pixels));
- values.put(IconDB.COLUMN_MONO_ICON, pixels);
- } else {
- values.put(IconDB.COLUMN_MONO_ICON, (byte[]) null);
- }
- } else {
- values.put(IconDB.COLUMN_ICON, (byte[]) null);
- values.put(IconDB.COLUMN_MONO_ICON, (byte[]) null);
- }
+ values.put(IconDB.COLUMN_ICON, bitmapInfo.toByteArray());
values.put(IconDB.COLUMN_ICON_COLOR, bitmapInfo.color);
- values.put(IconDB.COLUMN_FLAGS, bitmapInfo.flags);
values.put(IconDB.COLUMN_LABEL, label);
values.put(IconDB.COLUMN_SYSTEM_STATE, getIconSystemState(packageName));
diff --git a/iconloaderlib/src/com/android/launcher3/util/FlagOp.java b/iconloaderlib/src/com/android/launcher3/util/FlagOp.java
deleted file mode 100644
index 65117ca..0000000
--- a/iconloaderlib/src/com/android/launcher3/util/FlagOp.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright (C) 2022 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.util;
-
-/**
- * Utility interface for representing flag operations
- */
-public interface FlagOp {
-
- FlagOp NO_OP = i -> i;
-
- int apply(int flags);
-
- /**
- * Returns a new OP which adds the provided flag after applying all previous operations
- */
- default FlagOp addFlag(int flag) {
- return i -> apply(i) | flag;
- }
-
- /**
- * Returns a new OP which removes the provided flag after applying all previous operations
- */
- default FlagOp removeFlag(int flag) {
- return i -> apply(i) & ~flag;
- }
-
- /**
- * Returns a new OP which adds or removed the provided flag based on {@code enable} after
- * applying all previous operations
- */
- default FlagOp setFlag(int flag, boolean enable) {
- return enable ? addFlag(flag) : removeFlag(flag);
- }
-}
diff --git a/searchuilib/build.gradle b/searchuilib/build.gradle
index 3bf65fe..4f372e3 100644
--- a/searchuilib/build.gradle
+++ b/searchuilib/build.gradle
@@ -7,6 +7,8 @@ android {
defaultConfig {
minSdkVersion 25
targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
}
sourceSets {
diff --git a/searchuilib/src/com/android/app/search/LayoutType.java b/searchuilib/src/com/android/app/search/LayoutType.java
index d7c28ab..cf27e2b 100644
--- a/searchuilib/src/com/android/app/search/LayoutType.java
+++ b/searchuilib/src/com/android/app/search/LayoutType.java
@@ -43,9 +43,7 @@ public class LayoutType {
// will replace ICON_DOUBLE_* ICON_SINGLE_* layouts
public static final String ICON_HORIZONTAL_TEXT = "icon_row";
public static final String HORIZONTAL_MEDIUM_TEXT = "icon_row_medium";
- public static final String EXTRA_TALL_ICON_ROW = "extra_tall_icon_row";
public static final String SMALL_ICON_HORIZONTAL_TEXT = "short_icon_row";
- public static final String SMALL_ICON_HORIZONTAL_TEXT_THUMBNAIL = "short_icon_row_thumbnail";
// This layout creates square thumbnail image (currently 3 column)
public static final String THUMBNAIL = "thumbnail";
@@ -73,7 +71,4 @@ public class LayoutType {
// layout representing quick calculations
public static final String CALCULATOR = "calculator";
-
- // layout for the section header
- public static final String SECTION_HEADER = "section_header";
}
diff --git a/searchuilib/src/com/android/app/search/ResultType.java b/searchuilib/src/com/android/app/search/ResultType.java
deleted file mode 100644
index 1e5ea12..0000000
--- a/searchuilib/src/com/android/app/search/ResultType.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2020 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.app.search;
-
-/**
- * Constants to be used with {@link android.app.search.SearchContext} and
- * {@link android.app.search.SearchTarget}.
- *
- * Note, a result type could be a of two types.
- * For example, unpublished settings result type could be in slices:
- * <code> resultType = SETTING | SLICE </code>
- */
-public class ResultType {
-
- // published corpus by 3rd party app, supported by SystemService
- public static final int APPLICATION = 1 << 0;
- public static final int SHORTCUT = 1 << 1;
- public static final int SLICE = 1 << 6;
- public static final int WIDGETS = 1 << 7;
-
- // Not extracted from any of the SystemService
- public static final int PEOPLE = 1 << 2;
- public static final int ACTION = 1 << 3;
- public static final int SETTING = 1 << 4;
- public static final int SCREENSHOT = 1 << 5;
- public static final int PLAY = 1 << 8;
- public static final int SUGGEST = 1 << 9;
- public static final int ASSISTANT = 1 << 10;
- public static final int CHROMETAB = 1 << 11;
- public static final int NAVVYSITE = 1 << 12;
- public static final int TIPS = 1 << 13;
- public static final int PEOPLE_TILE = 1 << 14;
- public static final int LEGACY_SHORTCUT = 1 << 15;
- public static final int MEMORY = 1 << 16;
- public static final int WEB_SUGGEST = 1 << 17;
-}