Snap for 12763142 from 168514eb3f8cd694233262d9ae3419ea736dcbaa to 25Q1-release
Change-Id: Ib8b3d4dbc238a677f90cb90db202c45687933441
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index ad062d2..f3f9d1e 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -87,7 +87,7 @@
protected final int mFullResIconDpi;
protected final int mIconBitmapSize;
- protected boolean mMonoIconEnabled;
+ protected IconThemeController mThemeController;
@Nullable
private IconNormalizer mNormalizer;
@@ -144,6 +144,11 @@
return mNormalizer;
}
+ @Nullable
+ public IconThemeController getThemeController() {
+ return mThemeController;
+ }
+
public int getFullResIconDpi() {
return mFullResIconDpi;
}
@@ -237,30 +242,13 @@
if (adaptiveIcon instanceof BitmapInfo.Extender extender) {
info = extender.getExtendedInfo(bitmap, color, this, scale[0]);
- } else if (IconProvider.ATLEAST_T && mMonoIconEnabled) {
- Drawable mono = getMonochromeDrawable(adaptiveIcon);
- if (mono != null) {
- info.setMonoIcon(createIconBitmap(mono, scale[0], MODE_ALPHA), this);
- }
+ } else if (IconProvider.ATLEAST_T && mThemeController != null && adaptiveIcon != null) {
+ info.setThemedBitmap(mThemeController.createThemedBitmap(adaptiveIcon, info, this));
}
info = info.withFlags(getBitmapFlagOp(options));
return info;
}
- /**
- * Returns a monochromatic version of the given drawable or null, if it is not supported
- *
- * @param base the original icon
- */
- @TargetApi(Build.VERSION_CODES.TIRAMISU)
- protected Drawable getMonochromeDrawable(AdaptiveIconDrawable base) {
- Drawable mono = base.getMonochrome();
- if (mono != null) {
- return new ClippedMonoDrawable(mono);
- }
- return null;
- }
-
@NonNull
public FlagOp getBitmapFlagOp(@Nullable IconOptions options) {
FlagOp op = FlagOp.NO_OP;
@@ -386,7 +374,7 @@
}
@NonNull
- protected Bitmap createIconBitmap(@Nullable final Drawable icon, final float scale,
+ public Bitmap createIconBitmap(@Nullable final Drawable icon, final float scale,
@BitmapGenerationMode int bitmapGenerationMode) {
final int size = mIconBitmapSize;
final Bitmap bitmap;
@@ -610,26 +598,6 @@
}
}
- protected static class ClippedMonoDrawable extends InsetDrawable {
-
- @NonNull
- private final AdaptiveIconDrawable mCrop;
-
- public ClippedMonoDrawable(@Nullable final 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);
- }
- }
-
private static class CenterTextDrawable extends ColorDrawable {
@NonNull
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java b/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
index 2767e12..480061a 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
@@ -60,8 +60,7 @@
public final int color;
@Nullable
- protected Bitmap mMono;
- protected Bitmap mWhiteShadowLayer;
+ private ThemedBitmap mThemedBitmap;
public @BitmapInfoFlags int flags;
private BitmapInfo badgeInfo;
@@ -90,8 +89,7 @@
}
protected BitmapInfo copyInternalsTo(BitmapInfo target) {
- target.mMono = mMono;
- target.mWhiteShadowLayer = mWhiteShadowLayer;
+ target.mThemedBitmap = mThemedBitmap;
target.flags = flags;
target.badgeInfo = badgeInfo;
return target;
@@ -102,9 +100,13 @@
return copyInternalsTo(new BitmapInfo(icon, color));
}
- public void setMonoIcon(Bitmap mono, BaseIconFactory iconFactory) {
- mMono = mono;
- mWhiteShadowLayer = iconFactory.getWhiteShadowLayer();
+ public void setThemedBitmap(@Nullable ThemedBitmap themedBitmap) {
+ mThemedBitmap = themedBitmap;
+ }
+
+ @Nullable
+ public ThemedBitmap getThemedBitmap() {
+ return mThemedBitmap;
}
/**
@@ -125,10 +127,6 @@
return !isNullOrLowRes();
}
- public Bitmap getMono() {
- return mMono;
- }
-
/**
* Creates a drawable for the provided BitmapInfo
*/
@@ -143,8 +141,8 @@
FastBitmapDrawable drawable;
if (isLowRes()) {
drawable = new PlaceHolderIconDrawable(this, context);
- } else if ((creationFlags & FLAG_THEMED) != 0 && mMono != null) {
- drawable = ThemedIconDrawable.newDrawable(this, context);
+ } else if ((creationFlags & FLAG_THEMED) != 0 && mThemedBitmap != null) {
+ drawable = mThemedBitmap.newDrawable(this, context);
} else {
drawable = new FastBitmapDrawable(this);
}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java b/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java
index b625f3a..664294e 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java
@@ -22,7 +22,6 @@
import android.content.pm.ApplicationInfo;
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;
@@ -39,11 +38,8 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
-import android.util.TypedValue;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.icons.IconProvider.ThemeData;
+import com.android.launcher3.icons.mono.ThemedIconDrawable;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
@@ -53,7 +49,6 @@
* Wrapper over {@link AdaptiveIconDrawable} to intercept icon flattening logic for dynamic
* clock icons
*/
-@TargetApi(Build.VERSION_CODES.O)
public class ClockDrawableWrapper extends AdaptiveIconDrawable implements BitmapInfo.Extender {
public static boolean sRunningInTest = false;
@@ -94,34 +89,6 @@
super(base.getBackground(), base.getForeground());
}
- private void applyThemeData(ThemeData themeData) {
- if (!IconProvider.ATLEAST_T || mThemeInfo != null) {
- return;
- }
- try {
- TypedArray ta = themeData.mResources.obtainTypedArray(themeData.mResID);
- int count = ta.length();
- Bundle extras = new Bundle();
- for (int i = 0; i < count; i += 2) {
- TypedValue v = ta.peekValue(i + 1);
- extras.putInt(ta.getString(i), v.type >= TypedValue.TYPE_FIRST_INT
- && v.type <= TypedValue.TYPE_LAST_INT
- ? 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);
- });
- if (drawable != null) {
- mThemeInfo = drawable.mAnimationInfo;
- }
- } catch (Exception e) {
- Log.e(TAG, "Error loading themed clock", e);
- }
- }
-
@Override
public Drawable getMonochrome() {
if (mThemeInfo == null) {
@@ -140,26 +107,19 @@
* 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) {
+ 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);
- ClockDrawableWrapper wrapper = forExtras(appInfo.metaData,
- resId -> res.getDrawableForDensity(resId, iconDpi));
- if (wrapper != null && themeData != null) {
- wrapper.applyThemeData(themeData);
- }
- return wrapper;
+ return forExtras(appInfo.metaData, resId -> res.getDrawableForDensity(resId, iconDpi));
} 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) {
if (metadata == null) {
@@ -220,7 +180,7 @@
BaseIconFactory.MODE_HARDWARE_WITH_SHADOW);
// Only pass theme info if mono-icon is enabled
- AnimationInfo themeInfo = iconFactory.mMonoIconEnabled ? mThemeInfo : null;
+ AnimationInfo themeInfo = iconFactory.getThemeController() != null ? mThemeInfo : null;
Bitmap themeBG = themeInfo == null ? null : iconFactory.getWhiteShadowLayer();
return new ClockBitmapInfo(bitmap, color, normalizationScale,
mAnimationInfo, flattenBG, themeInfo, themeBG);
diff --git a/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java b/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java
index 0e37ca9..50ca8d6 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java
@@ -73,7 +73,7 @@
@VisibleForTesting protected boolean mIsPressed;
@VisibleForTesting protected boolean mIsHovered;
protected boolean mIsDisabled;
- float mDisabledAlpha = 1f;
+ protected float mDisabledAlpha = 1f;
@DrawableCreationFlags int mCreationFlags = 0;
diff --git a/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java b/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
index 15b5b21..594db35 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
@@ -151,7 +151,7 @@
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 = ClockDrawableWrapper.forPackage(mContext, mClock.getPackageName(), iconDpi);
}
if (icon == null) {
icon = loadPackageIcon(info, appInfo, iconDpi);
diff --git a/iconloaderlib/src/com/android/launcher3/icons/MonochromeIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/MonochromeIconFactory.java
index 2854d51..dc4ded8 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/MonochromeIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/MonochromeIconFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -35,7 +35,7 @@
import androidx.annotation.WorkerThread;
-import com.android.launcher3.icons.BaseIconFactory.ClippedMonoDrawable;
+import com.android.launcher3.icons.mono.MonoIconThemeController.ClippedMonoDrawable;
import java.nio.ByteBuffer;
@@ -59,7 +59,7 @@
private final Paint mDrawPaint;
private final Rect mSrcRect;
- MonochromeIconFactory(int iconBitmapSize) {
+ public MonochromeIconFactory(int iconBitmapSize) {
float extraFactor = AdaptiveIconDrawable.getExtraInsetFraction();
float viewPortScale = 1 / (1 + 2 * extraFactor);
mBitmapSize = Math.round(iconBitmapSize * 2 * viewPortScale);
diff --git a/iconloaderlib/src/com/android/launcher3/icons/ThemedBitmap.kt b/iconloaderlib/src/com/android/launcher3/icons/ThemedBitmap.kt
new file mode 100644
index 0000000..27b4619
--- /dev/null
+++ b/iconloaderlib/src/com/android/launcher3/icons/ThemedBitmap.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.icons
+
+import android.content.Context
+import android.graphics.drawable.AdaptiveIconDrawable
+
+/** Represents a themed version of a BitmapInfo */
+interface ThemedBitmap {
+
+ /** Creates a new Drawable */
+ fun newDrawable(info: BitmapInfo, context: Context): FastBitmapDrawable
+
+ fun serialize(): ByteArray
+}
+
+interface IconThemeController {
+
+ fun createThemedBitmap(
+ icon: AdaptiveIconDrawable,
+ info: BitmapInfo,
+ factory: BaseIconFactory,
+ ): ThemedBitmap?
+
+ fun decode(data: ByteArray, info: BitmapInfo, factory: BaseIconFactory): ThemedBitmap?
+
+ fun createThemedAdaptiveIcon(
+ context: Context,
+ originalIcon: AdaptiveIconDrawable,
+ info: BitmapInfo?,
+ ): AdaptiveIconDrawable?
+}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
index 4142a24..959f14d 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
@@ -59,13 +59,14 @@
import com.android.launcher3.icons.BaseIconFactory.IconOptions;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconProvider;
+import com.android.launcher3.icons.IconThemeController;
+import com.android.launcher3.icons.ThemedBitmap;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.SQLiteCacheHelper;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.nio.ByteBuffer;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collections;
@@ -692,20 +693,13 @@
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);
+ // Decode theme bitmap
+ try (BaseIconFactory factory = getIconFactory()) {
+ IconThemeController themeController = factory.getThemeController();
+ data = c.getBlob(IconDB.INDEX_MONO_ICON);
+ if (themeController != null && data != null) {
+ entry.bitmap.setThemedBitmap(
+ themeController.decode(data, entry.bitmap, factory));
}
}
}
@@ -792,17 +786,9 @@
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);
- }
+ ThemedBitmap themedBitmap = bitmapInfo.getThemedBitmap();
+ values.put(IconDB.COLUMN_MONO_ICON,
+ themedBitmap != null ? themedBitmap.serialize() : null);
} else {
values.put(IconDB.COLUMN_ICON, (byte[]) null);
values.put(IconDB.COLUMN_MONO_ICON, (byte[]) null);
diff --git a/iconloaderlib/src/com/android/launcher3/icons/mono/MonoIconThemeController.kt b/iconloaderlib/src/com/android/launcher3/icons/mono/MonoIconThemeController.kt
new file mode 100644
index 0000000..cdaf05f
--- /dev/null
+++ b/iconloaderlib/src/com/android/launcher3/icons/mono/MonoIconThemeController.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 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.icons.mono
+
+import android.annotation.TargetApi
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Bitmap.Config.ALPHA_8
+import android.graphics.Bitmap.Config.HARDWARE
+import android.graphics.BlendMode.SRC_IN
+import android.graphics.BlendModeColorFilter
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.drawable.AdaptiveIconDrawable
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.InsetDrawable
+import android.os.Build
+import com.android.launcher3.Flags
+import com.android.launcher3.icons.BaseIconFactory
+import com.android.launcher3.icons.BitmapInfo
+import com.android.launcher3.icons.IconThemeController
+import com.android.launcher3.icons.MonochromeIconFactory
+import com.android.launcher3.icons.ThemedBitmap
+import com.android.launcher3.icons.mono.ThemedIconDrawable.Companion.getColors
+import java.nio.ByteBuffer
+
+@TargetApi(Build.VERSION_CODES.TIRAMISU)
+class MonoIconThemeController : IconThemeController {
+
+ override fun createThemedBitmap(
+ icon: AdaptiveIconDrawable,
+ info: BitmapInfo,
+ factory: BaseIconFactory,
+ ): ThemedBitmap? {
+ val mono = getMonochromeDrawable(icon, info)
+ if (mono != null) {
+ val scale =
+ factory.normalizer.getScale(
+ AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null),
+ null,
+ null,
+ null,
+ )
+ return MonoThemedBitmap(
+ factory.createIconBitmap(mono, scale, BaseIconFactory.MODE_ALPHA),
+ factory.whiteShadowLayer,
+ )
+ }
+ return null
+ }
+
+ /**
+ * Returns a monochromatic version of the given drawable or null, if it is not supported
+ *
+ * @param base the original icon
+ */
+ private fun getMonochromeDrawable(base: AdaptiveIconDrawable, info: BitmapInfo): Drawable? {
+ val mono = base.monochrome
+ if (mono != null) {
+ return ClippedMonoDrawable(mono)
+ }
+ if (Flags.forceMonochromeAppIcons()) {
+ return MonochromeIconFactory(info.icon.width).wrap(base)
+ }
+ return null
+ }
+
+ override fun decode(
+ data: ByteArray,
+ info: BitmapInfo,
+ factory: BaseIconFactory,
+ ): ThemedBitmap? {
+ val icon = info.icon
+ if (data.size != icon.height * icon.width) return null
+
+ var monoBitmap = Bitmap.createBitmap(icon.width, icon.height, ALPHA_8)
+ monoBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(data))
+
+ val hwMonoBitmap = monoBitmap.copy(HARDWARE, false /*isMutable*/)
+ if (hwMonoBitmap != null) {
+ monoBitmap.recycle()
+ monoBitmap = hwMonoBitmap
+ }
+ return MonoThemedBitmap(monoBitmap, factory.whiteShadowLayer)
+ }
+
+ override fun createThemedAdaptiveIcon(
+ context: Context,
+ originalIcon: AdaptiveIconDrawable,
+ info: BitmapInfo?,
+ ): AdaptiveIconDrawable? {
+ val colors = getColors(context)
+ originalIcon.mutate()
+ var monoDrawable = originalIcon.monochrome?.apply { setTint(colors[1]) }
+
+ if (monoDrawable == null) {
+ info?.themedBitmap?.let { themedBitmap ->
+ if (themedBitmap is MonoThemedBitmap) {
+ // Inject a previously generated monochrome icon
+ // Use BitmapDrawable instead of FastBitmapDrawable so that the colorState is
+ // preserved in constantState
+ // Inset the drawable according to the AdaptiveIconDrawable layers
+ monoDrawable =
+ InsetDrawable(
+ BitmapDrawable(themedBitmap.mono).apply {
+ colorFilter = BlendModeColorFilter(colors[1], SRC_IN)
+ },
+ AdaptiveIconDrawable.getExtraInsetFraction() / 2,
+ )
+ }
+ }
+ }
+
+ return monoDrawable?.let { AdaptiveIconDrawable(ColorDrawable(colors[0]), it) }
+ }
+
+ class ClippedMonoDrawable(base: Drawable?) :
+ InsetDrawable(base, -AdaptiveIconDrawable.getExtraInsetFraction()) {
+ private val mCrop = AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null)
+
+ override fun draw(canvas: Canvas) {
+ mCrop.bounds = bounds
+ val saveCount = canvas.save()
+ canvas.clipPath(mCrop.iconMask)
+ super.draw(canvas)
+ canvas.restoreToCount(saveCount)
+ }
+ }
+}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/mono/MonoThemedBitmap.kt b/iconloaderlib/src/com/android/launcher3/icons/mono/MonoThemedBitmap.kt
new file mode 100644
index 0000000..dc6030e
--- /dev/null
+++ b/iconloaderlib/src/com/android/launcher3/icons/mono/MonoThemedBitmap.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.icons.mono
+
+import android.content.Context
+import android.graphics.Bitmap
+import com.android.launcher3.icons.BitmapInfo
+import com.android.launcher3.icons.FastBitmapDrawable
+import com.android.launcher3.icons.ThemedBitmap
+import com.android.launcher3.icons.mono.ThemedIconDrawable.ThemedConstantState
+import java.nio.ByteBuffer
+
+class MonoThemedBitmap(val mono: Bitmap, private val whiteShadowLayer: Bitmap) : ThemedBitmap {
+
+ override fun newDrawable(info: BitmapInfo, context: Context): FastBitmapDrawable {
+ val colors = ThemedIconDrawable.getColors(context)
+ return ThemedConstantState(info, mono, whiteShadowLayer, colors[0], colors[1]).newDrawable()
+ }
+
+ override fun serialize() =
+ ByteArray(mono.width * mono.height).apply { mono.copyPixelsToBuffer(ByteBuffer.wrap(this)) }
+}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.kt b/iconloaderlib/src/com/android/launcher3/icons/mono/ThemedIconDrawable.kt
similarity index 78%
rename from iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.kt
rename to iconloaderlib/src/com/android/launcher3/icons/mono/ThemedIconDrawable.kt
index 721b281..59fb245 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.kt
+++ b/iconloaderlib/src/com/android/launcher3/icons/mono/ThemedIconDrawable.kt
@@ -13,29 +13,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.icons
+package com.android.launcher3.icons.mono
import android.content.Context
+import android.graphics.Bitmap
import android.graphics.BlendMode.SRC_IN
import android.graphics.BlendModeColorFilter
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
+import com.android.launcher3.icons.BitmapInfo
+import com.android.launcher3.icons.FastBitmapDrawable
+import com.android.launcher3.icons.R
/** Class to handle monochrome themed app icons */
class ThemedIconDrawable(constantState: ThemedConstantState) :
- FastBitmapDrawable(constantState.mBitmap, constantState.colorFg) {
+ FastBitmapDrawable(constantState.getBitmap(), constantState.colorFg) {
val bitmapInfo = constantState.bitmapInfo
private val colorFg = constantState.colorFg
private val colorBg = constantState.colorBg
// The foreground/monochrome icon for the app
- private val monoIcon = bitmapInfo.mMono!!
+ private val monoIcon = constantState.mono
private val monoFilter = BlendModeColorFilter(colorFg, SRC_IN)
private val monoPaint =
Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG).apply { colorFilter = monoFilter }
- private val bgBitmap = bitmapInfo.mWhiteShadowLayer
+ private val bgBitmap = constantState.whiteShadowLayer
private val bgFilter = BlendModeColorFilter(colorBg, SRC_IN)
private val mBgPaint =
Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG).apply { colorFilter = bgFilter }
@@ -61,25 +65,27 @@
override fun isThemed() = true
- override fun newConstantState() = ThemedConstantState(bitmapInfo, colorBg, colorFg)
+ override fun newConstantState() =
+ ThemedConstantState(bitmapInfo, monoIcon, bgBitmap, colorBg, colorFg)
override fun getIconColor() = colorFg
- class ThemedConstantState(val bitmapInfo: BitmapInfo, val colorBg: Int, val colorFg: Int) :
- FastBitmapConstantState(bitmapInfo.icon, bitmapInfo.color) {
+ class ThemedConstantState(
+ val bitmapInfo: BitmapInfo,
+ val mono: Bitmap,
+ val whiteShadowLayer: Bitmap,
+ val colorBg: Int,
+ val colorFg: Int,
+ ) : FastBitmapConstantState(bitmapInfo.icon, bitmapInfo.color) {
public override fun createDrawable() = ThemedIconDrawable(this)
+
+ fun getBitmap(): Bitmap = mBitmap
}
companion object {
const val TAG: String = "ThemedIconDrawable"
- @JvmStatic
- fun newDrawable(info: BitmapInfo, context: Context): FastBitmapDrawable {
- val colors = getColors(context)
- return ThemedConstantState(info, colors[0], colors[1]).newDrawable()
- }
-
/** Get an int array representing background and foreground colors for themed icons */
@JvmStatic
fun getColors(context: Context): IntArray {
diff --git a/toruslib/torus-core/src/main/java/com/google/android/torus/core/wallpaper/LiveWallpaper.kt b/toruslib/torus-core/src/main/java/com/google/android/torus/core/wallpaper/LiveWallpaper.kt
index 6c072d0..533a95e 100644
--- a/toruslib/torus-core/src/main/java/com/google/android/torus/core/wallpaper/LiveWallpaper.kt
+++ b/toruslib/torus-core/src/main/java/com/google/android/torus/core/wallpaper/LiveWallpaper.kt
@@ -197,6 +197,16 @@
return false
}
+ /**
+ * Returns the information if the wallpaper is visible.
+ */
+ fun isVisible(): Boolean {
+ this.wallpaperServiceEngine?.let {
+ return it.isVisible
+ }
+ return false
+ }
+
/** Triggers the [WallpaperService] to recompute the Wallpaper Colors. */
fun notifyWallpaperColorsChanged() {
this.wallpaperServiceEngine?.notifyColorsChanged()
diff --git a/viewcapturelib/OWNERS b/viewcapturelib/OWNERS
index 30bdc84..2f30b7c 100644
--- a/viewcapturelib/OWNERS
+++ b/viewcapturelib/OWNERS
@@ -1,2 +1,3 @@
sunnygoyal@google.com
andonian@google.com
+include platform/development:/tools/winscope/OWNERS
diff --git a/viewcapturelib/src/com/android/app/viewcapture/ViewCapture.java b/viewcapturelib/src/com/android/app/viewcapture/ViewCapture.java
index 761b863..33f6a95 100644
--- a/viewcapturelib/src/com/android/app/viewcapture/ViewCapture.java
+++ b/viewcapturelib/src/com/android/app/viewcapture/ViewCapture.java
@@ -311,8 +311,12 @@
captureViewTree(mRoot, mViewPropertyRef);
ViewPropertyRef captured = mViewPropertyRef.next;
if (captured != null) {
- captured.callback = mCaptureCallback;
captured.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
+
+ // Main thread writes volatile field:
+ // guarantee that variable changes prior the field write are visible to bg thread
+ captured.volatileCallback = mCaptureCallback;
+
mBgExecutor.execute(captured);
}
mIsFirstFrame = false;
@@ -552,9 +556,11 @@
public ViewPropertyRef next;
- public Consumer<ViewPropertyRef> callback = null;
public long elapsedRealtimeNanos = 0;
+ // Volatile field to establish happens-before relationship between main and bg threads
+ // (see JSR-133: Java Memory Model and Thread Specification)
+ public volatile Consumer<ViewPropertyRef> volatileCallback = null;
public void transferFrom(View in) {
view = in;
@@ -651,8 +657,10 @@
@Override
public void run() {
- Consumer<ViewPropertyRef> oldCallback = callback;
- callback = null;
+ // Bg thread reads volatile field:
+ // guarantee that variable changes in main thread prior the field write are visible
+ Consumer<ViewPropertyRef> oldCallback = volatileCallback;
+ volatileCallback = null;
if (oldCallback != null) {
oldCallback.accept(this);
}