Adding support for listening to icon config changes
Bug: 183641907
Test: Manual
Change-Id: If1dbf346df34865db23c22c43a36ac9b4403bc18
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index 7265cb9..cc80de7 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -84,7 +84,7 @@
clear();
}
- protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) {
+ public BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) {
this(context, fillResIconDpi, iconBitmapSize, false);
}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java b/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
index cc463ba..6c96967 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
@@ -16,6 +16,9 @@
package com.android.launcher3.icons;
+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 android.content.BroadcastReceiver;
@@ -32,6 +35,7 @@
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
+import android.os.PatternMatcher;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -45,7 +49,8 @@
import org.xmlpull.v1.XmlPullParser;
import java.util.Calendar;
-import java.util.function.BiConsumer;
+import java.util.Collections;
+import java.util.Map;
import java.util.function.Supplier;
/**
@@ -53,6 +58,10 @@
*/
public class IconProvider {
+ private final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
+ 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";
@@ -65,7 +74,9 @@
private static final String SYSTEM_STATE_SEPARATOR = " ";
private static final String THEMED_ICON_MAP_FILE = "grayscale_icon_map";
- private ArrayMap<String, ThemeData> mThemedIconMap;
+ private static final Map<String, ThemeData> DISABLED_MAP = Collections.emptyMap();
+
+ private Map<String, ThemeData> mThemedIconMap;
private final Context mContext;
private final ComponentName mCalendar;
@@ -81,11 +92,18 @@
mClock = parseComponentOrNull(context, R.string.clock_component_name);
if (!supportsIconTheme) {
// Initialize an empty map if theming is not supported
- mThemedIconMap = new ArrayMap<>();
+ mThemedIconMap = DISABLED_MAP;
}
}
/**
+ * Enables or disables icon theme support
+ */
+ public void setIconThemeSupported(boolean isSupported) {
+ mThemedIconMap = isSupported ? null : DISABLED_MAP;
+ }
+
+ /**
* Adds any modification to the provided systemState for dynamic icons. This system state
* is used by caches to check for icon invalidation.
*/
@@ -98,15 +116,6 @@
}
/**
- * Loads the icon for the provided ActivityInfo such that it can be drawn directly
- * on the UI
- * @deprecated Use {@link #getIcon}
- */
- public Drawable getIconForUI(ActivityInfo info, UserHandle user) {
- return getIcon(info);
- }
-
- /**
* Loads the icon for the provided LauncherActivityInfo
*/
public Drawable getIcon(LauncherActivityInfo info, int iconDpi) {
@@ -165,7 +174,7 @@
return icon;
}
- private ArrayMap<String, ThemeData> getThemedIconMap() {
+ private Map<String, ThemeData> getThemedIconMap() {
if (mThemedIconMap != null) {
return mThemedIconMap;
}
@@ -260,60 +269,99 @@
return Calendar.getInstance().get(Calendar.DAY_OF_MONTH) - 1;
}
- /**
- * Registers a callback to listen for calendar icon changes.
- * The callback receives the packageName for the calendar icon
- */
- public static SafeCloseable registerIconChangeListener(Context context,
- BiConsumer<String, UserHandle> callback, Handler handler) {
- ComponentName calendar = parseComponentOrNull(context, R.string.calendar_component_name);
- ComponentName clock = parseComponentOrNull(context, R.string.clock_component_name);
-
- if (calendar == null && clock == null) {
- return () -> { };
- }
-
- BroadcastReceiver receiver = new DateTimeChangeReceiver(callback);
- final IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
- if (calendar != null) {
- filter.addAction(Intent.ACTION_TIME_CHANGED);
- filter.addAction(Intent.ACTION_DATE_CHANGED);
- }
- context.registerReceiver(receiver, filter, null, handler);
-
- return () -> context.unregisterReceiver(receiver);
+ private static ComponentName parseComponentOrNull(Context context, int resId) {
+ String cn = context.getString(resId);
+ return TextUtils.isEmpty(cn) ? null : ComponentName.unflattenFromString(cn);
}
- private static class DateTimeChangeReceiver extends BroadcastReceiver {
+ /**
+ * Returns a string representation of the current system icon state
+ */
+ public String getSystemIconState() {
+ return (CONFIG_ICON_MASK_RES_ID == ID_NULL
+ ? "" : mContext.getResources().getString(CONFIG_ICON_MASK_RES_ID))
+ + (mThemedIconMap == DISABLED_MAP ? ",no-theme" : ",with-theme");
+ }
- private final BiConsumer<String, UserHandle> mCallback;
+ /**
+ * Registers a callback to listen for various system dependent icon changes.
+ */
+ public SafeCloseable registerIconChangeListener(IconChangeListener listener, Handler handler) {
+ return new IconChangeReceiver(listener, handler);
+ }
- DateTimeChangeReceiver(BiConsumer<String, UserHandle> callback) {
+ private class IconChangeReceiver extends BroadcastReceiver implements SafeCloseable {
+
+ private final IconChangeListener mCallback;
+ private String mIconState;
+
+ IconChangeReceiver(IconChangeListener callback, Handler handler) {
mCallback = callback;
+ mIconState = getSystemIconState();
+
+
+ IntentFilter packageFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
+ packageFilter.addDataScheme("package");
+ packageFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
+ mContext.registerReceiver(this, packageFilter, null, handler);
+
+ if (mCalendar != null || mClock != null) {
+ final IntentFilter filter = new IntentFilter(ACTION_TIMEZONE_CHANGED);
+ if (mCalendar != null) {
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(ACTION_DATE_CHANGED);
+ }
+ mContext.registerReceiver(this, filter, null, handler);
+ }
}
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
- ComponentName clock = parseComponentOrNull(context, R.string.clock_component_name);
- if (clock != null) {
- mCallback.accept(clock.getPackageName(), Process.myUserHandle());
- }
- }
-
- ComponentName calendar =
- parseComponentOrNull(context, R.string.calendar_component_name);
- if (calendar != null) {
- for (UserHandle user
- : context.getSystemService(UserManager.class).getUserProfiles()) {
- mCallback.accept(calendar.getPackageName(), user);
+ switch (intent.getAction()) {
+ case ACTION_TIMEZONE_CHANGED:
+ if (mClock != null) {
+ mCallback.onAppIconChanged(mClock.getPackageName(), Process.myUserHandle());
+ }
+ // follow through
+ case ACTION_DATE_CHANGED:
+ case ACTION_TIME_CHANGED:
+ if (mCalendar != null) {
+ for (UserHandle user
+ : context.getSystemService(UserManager.class).getUserProfiles()) {
+ mCallback.onAppIconChanged(mCalendar.getPackageName(), user);
+ }
+ }
+ break;
+ case ACTION_OVERLAY_CHANGED: {
+ String newState = getSystemIconState();
+ if (!mIconState.equals(newState)) {
+ mIconState = newState;
+ mCallback.onSystemIconStateChanged(mIconState);
+ }
+ break;
}
}
}
+
+ @Override
+ public void close() {
+ mContext.unregisterReceiver(this);
+ }
}
- private static ComponentName parseComponentOrNull(Context context, int resId) {
- String cn = context.getString(resId);
- return TextUtils.isEmpty(cn) ? null : ComponentName.unflattenFromString(cn);
+ /**
+ * Listener for receiving icon changes
+ */
+ public interface IconChangeListener {
+
+ /**
+ * Called when the icon for a particular app changes
+ */
+ void onAppIconChanged(String packageName, UserHandle user);
+
+ /**
+ * Called when the global icon state changed, which can typically affect all icons
+ */
+ void onSystemIconStateChanged(String iconState);
}
}