Adding icon theming API support in Launcher

Bug: 200082620
Test: manual
Change-Id: If986b9cfc3db79d627d2a6f1304e1b6f58491470
This commit is contained in:
Sunny Goyal
2021-12-24 01:08:31 +05:30
parent 3b7ae6e723
commit 68af549a45
6 changed files with 152 additions and 27 deletions
@@ -36,6 +36,7 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIconProvider;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.pm.InstallSessionHelper;
@@ -61,7 +62,7 @@ public class LauncherAppState implements SafeCloseable {
private final Context mContext;
private final LauncherModel mModel;
private final IconProvider mIconProvider;
private final LauncherIconProvider mIconProvider;
private final IconCache mIconCache;
private final InvariantDeviceProfile mInvariantDeviceProfile;
private final RunnableList mOnTerminateCallback = new RunnableList();
@@ -138,7 +139,7 @@ public class LauncherAppState implements SafeCloseable {
mContext = context;
mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
mIconProvider = new IconProvider(context, Themes.isThemedIconEnabled(context));
mIconProvider = new LauncherIconProvider(context);
mIconCache = new IconCache(mContext, mInvariantDeviceProfile,
iconCacheFileName, mIconProvider);
mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext),
+16 -8
View File
@@ -76,9 +76,8 @@ import androidx.core.os.BuildCompat;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.graphics.GridCustomizationsProvider;
import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.ShortcutCachingLogic;
import com.android.launcher3.icons.ThemedIconDrawable;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.SearchActionItemInfo;
@@ -87,6 +86,7 @@ import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -123,8 +123,9 @@ public final class Utilities {
public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
public static final boolean ATLEAST_S = BuildCompat.isAtLeastS()
|| Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
public static final boolean ATLEAST_S = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
public static final boolean ATLEAST_T = BuildCompat.isAtLeastT();
/**
* Set on a motion event dispatched from the nav bar. See {@link MotionEvent#setEdgeFlags(int)}.
@@ -672,11 +673,19 @@ public final class Utilities {
* @param outObj this is set to the internal data associated with {@param info},
* eg {@link LauncherActivityInfo} or {@link ShortcutInfo}.
*/
@TargetApi(Build.VERSION_CODES.TIRAMISU)
public static Drawable getFullDrawable(Context context, ItemInfo info, int width, int height,
Object[] outObj) {
Drawable icon = loadFullDrawableWithoutTheme(context, info, width, height, outObj);
if (icon instanceof BitmapInfo.Extender) {
icon = ((BitmapInfo.Extender) icon).getThemedDrawable(context);
if (ATLEAST_T && icon instanceof AdaptiveIconDrawable) {
AdaptiveIconDrawable aid = (AdaptiveIconDrawable) icon.mutate();
Drawable mono = aid.getMonochrome();
if (mono != null && Themes.isThemedIconEnabled(context)) {
int[] colors = ThemedIconDrawable.getColors(context);
mono = mono.mutate();
mono.setTint(colors[1]);
return new AdaptiveIconDrawable(new ColorDrawable(colors[0]), mono);
}
}
return icon;
}
@@ -719,8 +728,7 @@ public final class Utilities {
return icon;
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION
&& info instanceof SearchActionItemInfo) {
return new AdaptiveIconDrawable(
new FastBitmapDrawable(((SearchActionItemInfo) info).bitmap), null);
return ((SearchActionItemInfo) info).bitmap.newIcon(context);
} else {
return null;
}
@@ -133,23 +133,25 @@ public class LauncherPreviewRenderer extends ContextWrapper
mObjectMap.put(InvariantDeviceProfile.INSTANCE, idp);
mObjectMap.put(LauncherAppState.INSTANCE,
new LauncherAppState(this, null /* iconCacheFileName */));
}
public LauncherIcons newLauncherIcons(Context context, boolean shapeDetection) {
/**
* Creates a new LauncherIcons for the preview, skipping the global pool
*/
public LauncherIcons newLauncherIcons(Context context) {
LauncherIconsForPreview launcherIconsForPreview = mIconPool.poll();
if (launcherIconsForPreview != null) {
return launcherIconsForPreview;
}
return new LauncherIconsForPreview(context, mIdp.fillResIconDpi, mIdp.iconBitmapSize,
-1 /* poolId */, shapeDetection);
-1 /* poolId */);
}
private final class LauncherIconsForPreview extends LauncherIcons {
private LauncherIconsForPreview(Context context, int fillResIconDpi, int iconBitmapSize,
int poolId, boolean shapeDetection) {
super(context, fillResIconDpi, iconBitmapSize, poolId, shapeDetection);
int poolId) {
super(context, fillResIconDpi, iconBitmapSize, poolId);
}
@Override
@@ -0,0 +1,102 @@
/*
* 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.icons;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
import org.xmlpull.v1.XmlPullParser;
import java.util.Collections;
import java.util.Map;
/**
* Extension of {@link IconProvider} with support for overriding theme icons
*/
public class LauncherIconProvider extends IconProvider {
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 = "LIconProvider";
private static final Map<String, ThemeData> DISABLED_MAP = Collections.emptyMap();
private Map<String, ThemeData> mThemedIconMap;
private boolean mSupportsIconTheme;
public LauncherIconProvider(Context context) {
super(context);
setIconThemeSupported(Themes.isThemedIconEnabled(context));
}
/**
* Enables or disables icon theme support
*/
public void setIconThemeSupported(boolean isSupported) {
mSupportsIconTheme = isSupported;
mThemedIconMap = isSupported ? null : DISABLED_MAP;
}
@Override
protected ThemeData getThemeDataForPackage(String packageName) {
return getThemedIconMap().get(packageName);
}
@Override
public String getSystemIconState() {
return super.getSystemIconState() + (mSupportsIconTheme ? ",with-theme" : ",no-theme");
}
private Map<String, ThemeData> getThemedIconMap() {
if (mThemedIconMap != null) {
return mThemedIconMap;
}
ArrayMap<String, ThemeData> map = new ArrayMap<>();
Resources res = mContext.getResources();
try (XmlResourceParser parser = res.getXml(R.xml.grayscale_icon_map)) {
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;
}
}
@@ -21,6 +21,7 @@ import android.content.Context;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.graphics.LauncherPreviewRenderer;
import com.android.launcher3.util.Themes;
/**
* Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
@@ -32,18 +33,13 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
private static LauncherIcons sPool;
private static int sPoolId = 0;
public static LauncherIcons obtain(Context context) {
return obtain(context, IconShape.getShape().enableShapeDetection());
}
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static LauncherIcons obtain(Context context, boolean shapeDetection) {
public static LauncherIcons obtain(Context context) {
if (context instanceof LauncherPreviewRenderer.PreviewContext) {
return ((LauncherPreviewRenderer.PreviewContext) context).newLauncherIcons(context,
shapeDetection);
return ((LauncherPreviewRenderer.PreviewContext) context).newLauncherIcons(context);
}
int poolId;
@@ -58,8 +54,7 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
}
InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId,
shapeDetection);
return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId);
}
public static void clearPool() {
@@ -73,9 +68,9 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
private LauncherIcons next;
protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId,
boolean shapeDetection) {
super(context, fillResIconDpi, iconBitmapSize, shapeDetection);
protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
super(context, fillResIconDpi, iconBitmapSize, IconShape.getShape().enableShapeDetection());
mMonoIconEnabled = Themes.isThemedIconEnabled(context);
mPoolId = poolId;
}