Adding ThemeManager as a centralized place for controlling icon theming
Bug: 381897614 Flag: EXEMPT refactor Test: atest ThemeManagerTest Change-Id: Ib1dafdcc303f05f78cf586741c3d35243ab06e69
This commit is contained in:
@@ -37,8 +37,9 @@ import android.os.UserHandle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.graphics.ThemeManager;
|
||||
import com.android.launcher3.graphics.ThemeManager.ThemeChangeListener;
|
||||
import com.android.launcher3.icons.IconProvider;
|
||||
import com.android.launcher3.icons.IconProvider.IconChangeListener;
|
||||
import com.android.launcher3.util.Executors.SimpleThreadFactory;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
@@ -66,9 +67,9 @@ import java.util.function.Predicate;
|
||||
* Singleton class to load and manage recents model.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
TaskStackChangeListener, TaskVisualsChangeListener, TaskVisualsChangeNotifier,
|
||||
SafeCloseable {
|
||||
public class RecentsModel implements RecentTasksDataSource, TaskStackChangeListener,
|
||||
TaskVisualsChangeListener, TaskVisualsChangeNotifier,
|
||||
ThemeChangeListener, SafeCloseable {
|
||||
|
||||
// We do not need any synchronization for this variable as its only written on UI thread.
|
||||
public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
|
||||
@@ -85,8 +86,10 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
private final TaskIconCache mIconCache;
|
||||
private final TaskThumbnailCache mThumbnailCache;
|
||||
private final ComponentCallbacks mCallbacks;
|
||||
private final ThemeManager mThemeManager;
|
||||
|
||||
private final TaskStackChangeListeners mTaskStackChangeListeners;
|
||||
private final SafeCloseable mIconChangeCloseable;
|
||||
|
||||
private RecentsModel(Context context) {
|
||||
this(context, new IconProvider(context));
|
||||
@@ -103,13 +106,15 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
new TaskIconCache(context, RECENTS_MODEL_EXECUTOR, iconProvider),
|
||||
new TaskThumbnailCache(context, RECENTS_MODEL_EXECUTOR),
|
||||
iconProvider,
|
||||
TaskStackChangeListeners.getInstance());
|
||||
TaskStackChangeListeners.getInstance(),
|
||||
ThemeManager.INSTANCE.get(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
RecentsModel(Context context, RecentTasksList taskList, TaskIconCache iconCache,
|
||||
TaskThumbnailCache thumbnailCache, IconProvider iconProvider,
|
||||
TaskStackChangeListeners taskStackChangeListeners) {
|
||||
TaskStackChangeListeners taskStackChangeListeners,
|
||||
ThemeManager themeManager) {
|
||||
mContext = context;
|
||||
mTaskList = taskList;
|
||||
mIconCache = iconCache;
|
||||
@@ -133,7 +138,10 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
|
||||
mTaskStackChangeListeners = taskStackChangeListeners;
|
||||
mTaskStackChangeListeners.registerTaskStackListener(this);
|
||||
iconProvider.registerIconChangeListener(this, MAIN_EXECUTOR.getHandler());
|
||||
mIconChangeCloseable = iconProvider.registerIconChangeListener(
|
||||
this::onAppIconChanged, MAIN_EXECUTOR.getHandler());
|
||||
mThemeManager = themeManager;
|
||||
themeManager.addChangeListener(this);
|
||||
}
|
||||
|
||||
public TaskIconCache getIconCache() {
|
||||
@@ -268,8 +276,7 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppIconChanged(String packageName, UserHandle user) {
|
||||
private void onAppIconChanged(String packageName, UserHandle user) {
|
||||
mIconCache.invalidateCacheEntries(packageName, user);
|
||||
for (TaskVisualsChangeListener listener : mThumbnailChangeListeners) {
|
||||
listener.onTaskIconChanged(packageName, user);
|
||||
@@ -284,7 +291,7 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSystemIconStateChanged(String iconState) {
|
||||
public void onThemeChanged() {
|
||||
mIconCache.clearCache();
|
||||
}
|
||||
|
||||
@@ -394,6 +401,8 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
}
|
||||
mIconCache.removeTaskVisualsChangeListener();
|
||||
mTaskStackChangeListeners.unregisterTaskStackListener(this);
|
||||
mIconChangeCloseable.close();
|
||||
mThemeManager.removeChangeListener(this);
|
||||
}
|
||||
|
||||
private boolean isCachePreloadingEnabled() {
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
|
||||
package com.android.quickstep.logging;
|
||||
|
||||
import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
|
||||
import static com.android.launcher3.LauncherPrefs.getDevicePrefs;
|
||||
import static com.android.launcher3.LauncherPrefs.getPrefs;
|
||||
import static com.android.launcher3.graphics.ThemeManager.KEY_THEMED_ICONS;
|
||||
import static com.android.launcher3.graphics.ThemeManager.THEMED_ICONS;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_DISABLED;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_DISABLED;
|
||||
@@ -29,7 +30,6 @@ import static com.android.launcher3.model.DeviceGridState.KEY_WORKSPACE_SIZE;
|
||||
import static com.android.launcher3.model.PredictionUpdateTask.LAST_PREDICTION_ENABLED;
|
||||
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
|
||||
import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
|
||||
import static com.android.launcher3.util.Themes.KEY_THEMED_ICONS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
+7
-4
@@ -21,8 +21,8 @@ import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.launcher3.LauncherPrefs
|
||||
import com.android.launcher3.LauncherPrefs.Companion.ALLOW_ROTATION
|
||||
import com.android.launcher3.LauncherPrefs.Companion.THEMED_ICONS
|
||||
import com.android.launcher3.SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY
|
||||
import com.android.launcher3.graphics.ThemeManager
|
||||
import com.android.launcher3.logging.InstanceId
|
||||
import com.android.launcher3.logging.StatsLogManager
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_NEW_APPS_TO_HOME_SCREEN_ENABLED
|
||||
@@ -66,16 +66,19 @@ class SettingsChangeLoggerTest {
|
||||
private var mDefaultThemedIcons = false
|
||||
private var mDefaultAllowRotation = false
|
||||
|
||||
private val themeManager: ThemeManager
|
||||
get() = ThemeManager.INSTANCE.get(mContext)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
whenever(mStatsLogManager.logger()).doReturn(mMockLogger)
|
||||
whenever(mStatsLogManager.logger().withInstanceId(any())).doReturn(mMockLogger)
|
||||
mDefaultThemedIcons = LauncherPrefs.get(mContext).get(THEMED_ICONS)
|
||||
mDefaultThemedIcons = themeManager.isMonoThemeEnabled
|
||||
mDefaultAllowRotation = LauncherPrefs.get(mContext).get(ALLOW_ROTATION)
|
||||
// To match the default value of THEMED_ICONS
|
||||
LauncherPrefs.get(mContext).put(THEMED_ICONS, false)
|
||||
themeManager.isMonoThemeEnabled = false
|
||||
// To match the default value of ALLOW_ROTATION
|
||||
LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = false)
|
||||
|
||||
@@ -84,7 +87,7 @@ class SettingsChangeLoggerTest {
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
LauncherPrefs.get(mContext).put(THEMED_ICONS, mDefaultThemedIcons)
|
||||
themeManager.isMonoThemeEnabled = mDefaultThemedIcons
|
||||
LauncherPrefs.get(mContext).put(ALLOW_ROTATION, mDefaultAllowRotation)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.graphics.ThemeManager;
|
||||
import com.android.launcher3.icons.IconProvider;
|
||||
import com.android.quickstep.util.GroupTask;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
@@ -93,7 +94,8 @@ public class RecentsModelTest {
|
||||
when(mThumbnailCache.isPreloadingEnabled()).thenReturn(true);
|
||||
|
||||
mRecentsModel = new RecentsModel(mContext, mTasksList, mock(TaskIconCache.class),
|
||||
mThumbnailCache, mock(IconProvider.class), mock(TaskStackChangeListeners.class));
|
||||
mThumbnailCache, mock(IconProvider.class), mock(TaskStackChangeListeners.class),
|
||||
mock(ThemeManager.class));
|
||||
|
||||
mResource = mock(Resources.class);
|
||||
when(mResource.getInteger((R.integer.recentsThumbnailCacheSize))).thenReturn(3);
|
||||
|
||||
@@ -464,8 +464,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
}
|
||||
|
||||
protected boolean shouldUseTheme() {
|
||||
return (mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER
|
||||
|| mDisplay == DISPLAY_TASKBAR) && Themes.isThemedIconEnabled(getContext());
|
||||
return mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER
|
||||
|| mDisplay == DISPLAY_TASKBAR;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,12 +20,6 @@ import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURC
|
||||
import static android.content.Context.RECEIVER_EXPORTED;
|
||||
|
||||
import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
|
||||
import static com.android.launcher3.InvariantDeviceProfile.GRID_NAME_PREFS_KEY;
|
||||
import static com.android.launcher3.LauncherPrefs.DB_FILE;
|
||||
import static com.android.launcher3.LauncherPrefs.GRID_NAME;
|
||||
import static com.android.launcher3.LauncherPrefs.ICON_STATE;
|
||||
import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
|
||||
import static com.android.launcher3.model.DeviceGridState.KEY_DB_FILE;
|
||||
import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
@@ -38,18 +32,17 @@ import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.LauncherApps.ArchiveCompatibilityParams;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.os.BuildCompat;
|
||||
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
import com.android.launcher3.graphics.ThemeManager;
|
||||
import com.android.launcher3.graphics.ThemeManager.ThemeChangeListener;
|
||||
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.logging.FileLog;
|
||||
import com.android.launcher3.model.ModelLauncherCallbacks;
|
||||
import com.android.launcher3.model.WidgetsFilterDataProvider;
|
||||
import com.android.launcher3.notification.NotificationListener;
|
||||
@@ -64,7 +57,6 @@ import com.android.launcher3.util.RunnableList;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.launcher3.util.SettingsCache;
|
||||
import com.android.launcher3.util.SimpleBroadcastReceiver;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
||||
|
||||
@@ -108,6 +100,11 @@ public class LauncherAppState implements SafeCloseable {
|
||||
}
|
||||
});
|
||||
|
||||
ThemeChangeListener themeChangeListener = this::refreshAndReloadLauncher;
|
||||
ThemeManager.INSTANCE.get(context).addChangeListener(themeChangeListener);
|
||||
mOnTerminateCallback.add(() ->
|
||||
ThemeManager.INSTANCE.get(context).removeChangeListener(themeChangeListener));
|
||||
|
||||
ModelLauncherCallbacks callbacks = mModel.newModelCallbacks();
|
||||
LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
|
||||
launcherApps.registerCallback(callbacks);
|
||||
@@ -156,14 +153,9 @@ public class LauncherAppState implements SafeCloseable {
|
||||
CustomWidgetManager cwm = CustomWidgetManager.INSTANCE.get(mContext);
|
||||
mOnTerminateCallback.add(cwm.addWidgetRefreshCallback(mModel::rebindCallbacks)::close);
|
||||
|
||||
IconObserver observer = new IconObserver();
|
||||
SafeCloseable iconChangeTracker = mIconProvider.registerIconChangeListener(
|
||||
observer, MODEL_EXECUTOR.getHandler());
|
||||
mModel::onAppIconChanged, MODEL_EXECUTOR.getHandler());
|
||||
mOnTerminateCallback.add(iconChangeTracker::close);
|
||||
MODEL_EXECUTOR.execute(observer::verifyIconChanged);
|
||||
LauncherPrefs.get(context).addListener(observer, THEMED_ICONS);
|
||||
mOnTerminateCallback.add(
|
||||
() -> LauncherPrefs.get(mContext).removeListener(observer, THEMED_ICONS));
|
||||
|
||||
InstallSessionTracker installSessionTracker =
|
||||
InstallSessionHelper.INSTANCE.get(context).registerInstallTracker(callbacks);
|
||||
@@ -255,41 +247,4 @@ public class LauncherAppState implements SafeCloseable {
|
||||
public static InvariantDeviceProfile getIDP(Context context) {
|
||||
return InvariantDeviceProfile.INSTANCE.get(context);
|
||||
}
|
||||
|
||||
private class IconObserver
|
||||
implements IconProvider.IconChangeListener, LauncherPrefChangeListener {
|
||||
|
||||
@Override
|
||||
public void onAppIconChanged(String packageName, UserHandle user) {
|
||||
mModel.onAppIconChanged(packageName, user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSystemIconStateChanged(String iconState) {
|
||||
IconShape.INSTANCE.get(mContext).pickBestShape(mContext);
|
||||
refreshAndReloadLauncher();
|
||||
LauncherPrefs.get(mContext).put(ICON_STATE, iconState);
|
||||
}
|
||||
|
||||
void verifyIconChanged() {
|
||||
String iconState = mIconProvider.getSystemIconState();
|
||||
if (!iconState.equals(LauncherPrefs.get(mContext).get(ICON_STATE))) {
|
||||
onSystemIconStateChanged(iconState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrefChanged(String key) {
|
||||
if (Themes.KEY_THEMED_ICONS.equals(key)) {
|
||||
mIconProvider.setIconThemeSupported(Themes.isThemedIconEnabled(mContext));
|
||||
verifyIconChanged();
|
||||
} else if (GRID_NAME_PREFS_KEY.equals(key)) {
|
||||
FileLog.d(TAG, "onPrefChanged GRID_NAME changed: "
|
||||
+ LauncherPrefs.get(mContext).get(GRID_NAME));
|
||||
} else if (KEY_DB_FILE.equals(key)) {
|
||||
FileLog.d(TAG, "onPrefChanged DB_FILE changed: "
|
||||
+ LauncherPrefs.get(mContext).get(DB_FILE));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import com.android.launcher3.settings.SettingsActivity
|
||||
import com.android.launcher3.states.RotationHelper
|
||||
import com.android.launcher3.util.DaggerSingletonObject
|
||||
import com.android.launcher3.util.DisplayController
|
||||
import com.android.launcher3.util.Themes
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
@@ -235,13 +234,9 @@ constructor(@ApplicationContext private val encryptedContext: Context) {
|
||||
const val TASKBAR_PINNING_KEY = "TASKBAR_PINNING_KEY"
|
||||
const val TASKBAR_PINNING_DESKTOP_MODE_KEY = "TASKBAR_PINNING_DESKTOP_MODE_KEY"
|
||||
const val SHOULD_SHOW_SMARTSPACE_KEY = "SHOULD_SHOW_SMARTSPACE_KEY"
|
||||
@JvmField
|
||||
val ICON_STATE = nonRestorableItem("pref_icon_shape_path", "", EncryptionType.ENCRYPTED)
|
||||
|
||||
@JvmField
|
||||
val ENABLE_TWOLINE_ALLAPPS_TOGGLE = backedUpItem("pref_enable_two_line_toggle", false)
|
||||
@JvmField
|
||||
val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.ENCRYPTED)
|
||||
@JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
|
||||
@JvmField val WORK_EDU_STEP = backedUpItem("showed_work_profile_edu", 0)
|
||||
@JvmField
|
||||
|
||||
@@ -74,9 +74,11 @@ import androidx.annotation.WorkerThread;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
|
||||
import com.android.launcher3.graphics.ThemeManager;
|
||||
import com.android.launcher3.graphics.TintedDrawableSpan;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.CacheableShortcutInfo;
|
||||
import com.android.launcher3.icons.IconThemeController;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
@@ -88,7 +90,6 @@ import com.android.launcher3.testing.shared.ResourceUtils;
|
||||
import com.android.launcher3.util.FlagOp;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.launcher3.widget.PendingAddShortcutInfo;
|
||||
@@ -626,7 +627,6 @@ public final class Utilities {
|
||||
@WorkerThread
|
||||
public static <T extends Context & ActivityContext> Pair<AdaptiveIconDrawable, Drawable>
|
||||
getFullDrawable(T context, ItemInfo info, int width, int height, boolean useTheme) {
|
||||
useTheme &= Themes.isThemedIconEnabled(context);
|
||||
LauncherAppState appState = LauncherAppState.getInstance(context);
|
||||
Drawable mainIcon = null;
|
||||
|
||||
@@ -690,15 +690,15 @@ public final class Utilities {
|
||||
|
||||
// Inject theme icon drawable
|
||||
if (ATLEAST_T && useTheme) {
|
||||
try (LauncherIcons li = LauncherIcons.obtain(context)) {
|
||||
if (li.getThemeController() != null) {
|
||||
AdaptiveIconDrawable themed = li.getThemeController().createThemedAdaptiveIcon(
|
||||
context,
|
||||
result,
|
||||
info instanceof ItemInfoWithIcon iiwi ? iiwi.bitmap : null);
|
||||
if (themed != null) {
|
||||
result = themed;
|
||||
}
|
||||
IconThemeController themeController =
|
||||
ThemeManager.INSTANCE.get(context).getThemeController();
|
||||
if (themeController != null) {
|
||||
AdaptiveIconDrawable themed = themeController.createThemedAdaptiveIcon(
|
||||
context,
|
||||
result,
|
||||
info instanceof ItemInfoWithIcon iiwi ? iiwi.bitmap : null);
|
||||
if (themed != null) {
|
||||
result = themed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener
|
||||
import com.android.launcher3.icons.BitmapInfo
|
||||
import com.android.launcher3.model.data.AppPairInfo
|
||||
import com.android.launcher3.util.Themes
|
||||
import com.android.launcher3.views.ActivityContext
|
||||
|
||||
/**
|
||||
@@ -46,12 +45,11 @@ constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
@JvmStatic
|
||||
fun composeDrawable(
|
||||
appPairInfo: AppPairInfo,
|
||||
p: AppPairIconDrawingParams
|
||||
p: AppPairIconDrawingParams,
|
||||
): AppPairIconDrawable {
|
||||
// Generate new icons, using themed flag if needed.
|
||||
val flags = if (Themes.isThemedIconEnabled(p.context)) BitmapInfo.FLAG_THEMED else 0
|
||||
val appIcon1 = appPairInfo.getFirstApp().newIcon(p.context, flags)
|
||||
val appIcon2 = appPairInfo.getSecondApp().newIcon(p.context, flags)
|
||||
// Generate new icons, using themed flag since the icon is drawn on homescreen
|
||||
val appIcon1 = appPairInfo.getFirstApp().newIcon(p.context, BitmapInfo.FLAG_THEMED)
|
||||
val appIcon2 = appPairInfo.getSecondApp().newIcon(p.context, BitmapInfo.FLAG_THEMED)
|
||||
appIcon1.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt())
|
||||
appIcon2.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt())
|
||||
|
||||
@@ -125,7 +123,7 @@ constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
((parentIcon.width - drawParams.backgroundSize) / 2).toInt(),
|
||||
// y-coordinate in parent's coordinate system
|
||||
(parentIcon.paddingTop + drawParams.standardIconPadding + drawParams.outerPadding)
|
||||
.toInt()
|
||||
.toInt(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -140,17 +138,13 @@ constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
drawable.draw(canvas)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scale of the icon background while hovered.
|
||||
*/
|
||||
/** Sets the scale of the icon background while hovered. */
|
||||
fun setHoverScale(scale: Float) {
|
||||
drawParams.hoverScale = scale
|
||||
redraw()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scale of the icon background while hovered.
|
||||
*/
|
||||
/** Gets the scale of the icon background while hovered. */
|
||||
fun getHoverScale(): Float {
|
||||
return drawParams.hoverScale
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.Context;
|
||||
import com.android.launcher3.LauncherPrefs;
|
||||
import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
import com.android.launcher3.graphics.ThemeManager;
|
||||
import com.android.launcher3.model.ItemInstallQueue;
|
||||
import com.android.launcher3.pm.InstallSessionHelper;
|
||||
import com.android.launcher3.util.ApiWrapper;
|
||||
@@ -64,6 +65,7 @@ public interface LauncherBaseAppComponent {
|
||||
MSDLPlayerWrapper getMSDLPlayerWrapper();
|
||||
WindowManagerProxy getWmProxy();
|
||||
LauncherPrefs getLauncherPrefs();
|
||||
ThemeManager getThemeManager();
|
||||
|
||||
/** Builder for LauncherBaseAppComponent. */
|
||||
interface Builder {
|
||||
|
||||
@@ -53,7 +53,6 @@ import com.android.launcher3.model.data.AppPairInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -448,8 +447,7 @@ public class PreviewItemManager {
|
||||
if (isActivePendingIcon(wii)) {
|
||||
p.drawable = newPendingIcon(mContext, wii);
|
||||
} else {
|
||||
p.drawable = wii.newIcon(mContext,
|
||||
Themes.isThemedIconEnabled(mContext) ? FLAG_THEMED : 0);
|
||||
p.drawable = wii.newIcon(mContext, FLAG_THEMED);
|
||||
}
|
||||
p.drawable.setBounds(0, 0, mIconSize, mIconSize);
|
||||
} else if (item instanceof AppPairInfo api) {
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
*/
|
||||
package com.android.launcher3.graphics;
|
||||
|
||||
import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.launcher3.util.Themes.isThemedIconEnabled;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
@@ -42,7 +40,6 @@ import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.InvariantDeviceProfile.GridOption;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.LauncherPrefs;
|
||||
import com.android.launcher3.model.BgDataModel;
|
||||
import com.android.launcher3.shapes.AppShape;
|
||||
import com.android.launcher3.shapes.AppShapesProvider;
|
||||
@@ -178,7 +175,8 @@ public class GridCustomizationsProvider extends ContentProvider {
|
||||
case GET_ICON_THEMED:
|
||||
case ICON_THEMED: {
|
||||
MatrixCursor cursor = new MatrixCursor(new String[]{BOOLEAN_VALUE});
|
||||
cursor.newRow().add(BOOLEAN_VALUE, isThemedIconEnabled(getContext()) ? 1 : 0);
|
||||
cursor.newRow().add(BOOLEAN_VALUE,
|
||||
ThemeManager.INSTANCE.get(getContext()).isMonoThemeEnabled() ? 1 : 0);
|
||||
return cursor;
|
||||
}
|
||||
default:
|
||||
@@ -247,8 +245,8 @@ public class GridCustomizationsProvider extends ContentProvider {
|
||||
}
|
||||
case ICON_THEMED:
|
||||
case SET_ICON_THEMED: {
|
||||
LauncherPrefs.get(context)
|
||||
.put(THEMED_ICONS, values.getAsBoolean(BOOLEAN_VALUE));
|
||||
ThemeManager.INSTANCE.get(context)
|
||||
.setMonoThemeEnabled(values.getAsBoolean(BOOLEAN_VALUE));
|
||||
context.getContentResolver().notifyChange(uri, null);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -36,9 +36,11 @@ import com.android.launcher3.anim.RoundedRectRevealOutlineProvider
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.dagger.LauncherAppComponent
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.graphics.ThemeManager.ThemeChangeListener
|
||||
import com.android.launcher3.icons.GraphicsUtils
|
||||
import com.android.launcher3.icons.IconNormalizer
|
||||
import com.android.launcher3.util.DaggerSingletonObject
|
||||
import com.android.launcher3.util.DaggerSingletonTracker
|
||||
import com.android.launcher3.views.ClipPathView
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
@@ -47,7 +49,13 @@ import org.xmlpull.v1.XmlPullParserException
|
||||
|
||||
/** Abstract representation of the shape of an icon shape */
|
||||
@LauncherAppSingleton
|
||||
class IconShape @Inject constructor(@ApplicationContext context: Context) {
|
||||
class IconShape
|
||||
@Inject
|
||||
constructor(
|
||||
@ApplicationContext context: Context,
|
||||
themeManager: ThemeManager,
|
||||
lifeCycle: DaggerSingletonTracker,
|
||||
) {
|
||||
var shape: ShapeDelegate = Circle()
|
||||
private set
|
||||
|
||||
@@ -56,6 +64,10 @@ class IconShape @Inject constructor(@ApplicationContext context: Context) {
|
||||
|
||||
init {
|
||||
pickBestShape(context)
|
||||
|
||||
val changeListener = ThemeChangeListener { pickBestShape(context) }
|
||||
themeManager.addChangeListener(changeListener)
|
||||
lifeCycle.addCloseable { themeManager.removeChangeListener(changeListener) }
|
||||
}
|
||||
|
||||
/** Initializes the shape which is closest to the [AdaptiveIconDrawable] */
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.graphics
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import com.android.launcher3.EncryptionType
|
||||
import com.android.launcher3.LauncherPrefChangeListener
|
||||
import com.android.launcher3.LauncherPrefs
|
||||
import com.android.launcher3.LauncherPrefs.Companion.backedUpItem
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.dagger.LauncherAppComponent
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.icons.IconThemeController
|
||||
import com.android.launcher3.icons.mono.MonoIconThemeController
|
||||
import com.android.launcher3.util.DaggerSingletonObject
|
||||
import com.android.launcher3.util.DaggerSingletonTracker
|
||||
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
|
||||
import com.android.launcher3.util.SimpleBroadcastReceiver
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Centralized class for managing Launcher icon theming */
|
||||
@LauncherAppSingleton
|
||||
open class ThemeManager
|
||||
@Inject
|
||||
constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val prefs: LauncherPrefs,
|
||||
lifecycle: DaggerSingletonTracker,
|
||||
) {
|
||||
|
||||
/** Representation of the current icon state */
|
||||
var iconState = parseIconState()
|
||||
private set
|
||||
|
||||
var isMonoThemeEnabled
|
||||
set(value) = prefs.put(THEMED_ICONS, value)
|
||||
get() = prefs.get(THEMED_ICONS)
|
||||
|
||||
var themeController: IconThemeController? =
|
||||
if (isMonoThemeEnabled) MonoIconThemeController() else null
|
||||
private set
|
||||
|
||||
private val listeners = CopyOnWriteArrayList<ThemeChangeListener>()
|
||||
|
||||
init {
|
||||
val receiver = SimpleBroadcastReceiver(MAIN_EXECUTOR) { verifyIconState() }
|
||||
receiver.registerPkgActions(context, "android", ACTION_OVERLAY_CHANGED)
|
||||
|
||||
val prefListener = LauncherPrefChangeListener { key ->
|
||||
if (key == THEMED_ICONS.sharedPrefKey) verifyIconState()
|
||||
}
|
||||
prefs.addListener(prefListener, THEMED_ICONS)
|
||||
|
||||
lifecycle.addCloseable {
|
||||
receiver.unregisterReceiverSafely(context)
|
||||
prefs.removeListener(prefListener)
|
||||
}
|
||||
}
|
||||
|
||||
private fun verifyIconState() {
|
||||
val newState = parseIconState()
|
||||
if (newState == iconState) return
|
||||
|
||||
iconState = newState
|
||||
themeController = if (isMonoThemeEnabled) MonoIconThemeController() else null
|
||||
|
||||
listeners.forEach { it.onThemeChanged() }
|
||||
}
|
||||
|
||||
fun addChangeListener(listener: ThemeChangeListener) = listeners.add(listener)
|
||||
|
||||
fun removeChangeListener(listener: ThemeChangeListener) = listeners.remove(listener)
|
||||
|
||||
private fun parseIconState() =
|
||||
IconState(
|
||||
iconMask =
|
||||
if (CONFIG_ICON_MASK_RES_ID == Resources.ID_NULL) ""
|
||||
else context.resources.getString(CONFIG_ICON_MASK_RES_ID),
|
||||
isMonoTheme = isMonoThemeEnabled,
|
||||
)
|
||||
|
||||
data class IconState(
|
||||
val iconMask: String,
|
||||
val isMonoTheme: Boolean,
|
||||
val themeCode: String = if (isMonoTheme) "with-theme" else "no-theme",
|
||||
) {
|
||||
fun toUniqueId() = "${iconMask.hashCode()},$themeCode"
|
||||
}
|
||||
|
||||
/** Interface for receiving theme change events */
|
||||
fun interface ThemeChangeListener {
|
||||
fun onThemeChanged()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmField val INSTANCE = DaggerSingletonObject(LauncherAppComponent::getThemeManager)
|
||||
|
||||
const val KEY_THEMED_ICONS = "themed_icons"
|
||||
@JvmField val THEMED_ICONS = backedUpItem(KEY_THEMED_ICONS, false, EncryptionType.ENCRYPTED)
|
||||
|
||||
private const val ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"
|
||||
private val CONFIG_ICON_MASK_RES_ID: Int =
|
||||
Resources.getSystem().getIdentifier("config_icon_mask", "string", "android")
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,8 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.graphics.ThemeManager;
|
||||
import com.android.launcher3.util.ApiWrapper;
|
||||
import com.android.launcher3.util.Themes;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
@@ -48,18 +48,16 @@ public class LauncherIconProvider extends IconProvider {
|
||||
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));
|
||||
setIconThemeSupported(ThemeManager.INSTANCE.get(context).isMonoThemeEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables icon theme support
|
||||
*/
|
||||
public void setIconThemeSupported(boolean isSupported) {
|
||||
mSupportsIconTheme = isSupported;
|
||||
mThemedIconMap = isSupported && FeatureFlags.USE_LOCAL_ICON_OVERRIDES.get()
|
||||
? null : DISABLED_MAP;
|
||||
}
|
||||
@@ -70,8 +68,9 @@ public class LauncherIconProvider extends IconProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSystemIconState() {
|
||||
return super.getSystemIconState() + (mSupportsIconTheme ? ",with-theme" : ",no-theme");
|
||||
public void updateSystemState() {
|
||||
super.updateSystemState();
|
||||
mSystemState += "," + ThemeManager.INSTANCE.get(mContext).getIconState().toUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,11 +23,10 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
import com.android.launcher3.icons.mono.MonoIconThemeController;
|
||||
import com.android.launcher3.graphics.ThemeManager;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.UserIconInfo;
|
||||
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
@@ -59,9 +58,7 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
|
||||
ConcurrentLinkedQueue<LauncherIcons> pool) {
|
||||
super(context, fillResIconDpi, iconBitmapSize,
|
||||
IconShape.INSTANCE.get(context).getShape().enableShapeDetection());
|
||||
if (Themes.isThemedIconEnabled(context)) {
|
||||
mThemeController = new MonoIconThemeController();
|
||||
}
|
||||
mThemeController = ThemeManager.INSTANCE.get(context).getThemeController();
|
||||
mPool = pool;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ package com.android.launcher3.util;
|
||||
import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_TEXT;
|
||||
import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_THEME;
|
||||
|
||||
import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
@@ -32,7 +30,6 @@ import android.util.TypedValue;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
|
||||
import com.android.launcher3.LauncherPrefs;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.icons.GraphicsUtils;
|
||||
@@ -44,8 +41,6 @@ import com.android.launcher3.views.ActivityContext;
|
||||
@SuppressWarnings("NewApi")
|
||||
public class Themes {
|
||||
|
||||
public static final String KEY_THEMED_ICONS = "themed_icons";
|
||||
|
||||
/** Gets the WallpaperColorHints and then uses those to get the correct activity theme res. */
|
||||
public static int getActivityThemeRes(Context context) {
|
||||
return getActivityThemeRes(context, WallpaperColorHints.get(context).getHints());
|
||||
@@ -64,13 +59,6 @@ public class Themes {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if workspace icon theming is enabled
|
||||
*/
|
||||
public static boolean isThemedIconEnabled(Context context) {
|
||||
return LauncherPrefs.get(context).get(THEMED_ICONS);
|
||||
}
|
||||
|
||||
public static String getDefaultBodyFont(Context context) {
|
||||
TypedArray ta = context.obtainStyledAttributes(android.R.style.TextAppearance_DeviceDefault,
|
||||
new int[]{android.R.attr.fontFamily});
|
||||
|
||||
@@ -22,9 +22,8 @@ import android.os.Process
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.launcher3.LauncherAppState
|
||||
import com.android.launcher3.LauncherPrefs.Companion.THEMED_ICONS
|
||||
import com.android.launcher3.LauncherPrefs.Companion.get
|
||||
import com.android.launcher3.graphics.PreloadIconDrawable
|
||||
import com.android.launcher3.graphics.ThemeManager
|
||||
import com.android.launcher3.icons.BitmapInfo
|
||||
import com.android.launcher3.icons.FastBitmapDrawable
|
||||
import com.android.launcher3.icons.IconCache
|
||||
@@ -71,6 +70,9 @@ class PreviewItemManagerTest {
|
||||
|
||||
private var defaultThemedIcons = false
|
||||
|
||||
private val themeManager: ThemeManager
|
||||
get() = ThemeManager.INSTANCE.get(context)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
modelHelper = LauncherModelHelper()
|
||||
@@ -126,19 +128,19 @@ class PreviewItemManagerTest {
|
||||
folderItems[3].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK))
|
||||
folderItems[3].bitmap.themedBitmap = null
|
||||
|
||||
defaultThemedIcons = get(context).get(THEMED_ICONS)
|
||||
defaultThemedIcons = themeManager.isMonoThemeEnabled
|
||||
}
|
||||
|
||||
@After
|
||||
@Throws(Exception::class)
|
||||
fun tearDown() {
|
||||
get(context).put(THEMED_ICONS, defaultThemedIcons)
|
||||
themeManager.isMonoThemeEnabled = defaultThemedIcons
|
||||
modelHelper.destroy()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkThemedIconWithThemingOn_iconShouldBeThemed() {
|
||||
get(context).put(THEMED_ICONS, true)
|
||||
themeManager.isMonoThemeEnabled = true
|
||||
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
|
||||
|
||||
previewItemManager.setDrawable(drawingParams, folderItems[0])
|
||||
@@ -148,7 +150,7 @@ class PreviewItemManagerTest {
|
||||
|
||||
@Test
|
||||
fun checkThemedIconWithThemingOff_iconShouldNotBeThemed() {
|
||||
get(context).put(THEMED_ICONS, false)
|
||||
themeManager.isMonoThemeEnabled = false
|
||||
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
|
||||
|
||||
previewItemManager.setDrawable(drawingParams, folderItems[0])
|
||||
@@ -158,7 +160,7 @@ class PreviewItemManagerTest {
|
||||
|
||||
@Test
|
||||
fun checkUnthemedIconWithThemingOn_iconShouldNotBeThemed() {
|
||||
get(context).put(THEMED_ICONS, true)
|
||||
themeManager.isMonoThemeEnabled = true
|
||||
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
|
||||
|
||||
previewItemManager.setDrawable(drawingParams, folderItems[1])
|
||||
@@ -168,7 +170,7 @@ class PreviewItemManagerTest {
|
||||
|
||||
@Test
|
||||
fun checkUnthemedIconWithThemingOff_iconShouldNotBeThemed() {
|
||||
get(context).put(THEMED_ICONS, false)
|
||||
themeManager.isMonoThemeEnabled = false
|
||||
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
|
||||
|
||||
previewItemManager.setDrawable(drawingParams, folderItems[1])
|
||||
@@ -178,7 +180,7 @@ class PreviewItemManagerTest {
|
||||
|
||||
@Test
|
||||
fun checkThemedIconWithBadgeWithThemingOn_iconAndBadgeShouldBeThemed() {
|
||||
get(context).put(THEMED_ICONS, true)
|
||||
themeManager.isMonoThemeEnabled = true
|
||||
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
|
||||
|
||||
previewItemManager.setDrawable(drawingParams, folderItems[2])
|
||||
@@ -191,7 +193,7 @@ class PreviewItemManagerTest {
|
||||
|
||||
@Test
|
||||
fun checkUnthemedIconWithBadgeWithThemingOn_badgeShouldBeThemed() {
|
||||
get(context).put(THEMED_ICONS, true)
|
||||
themeManager.isMonoThemeEnabled = true
|
||||
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
|
||||
|
||||
previewItemManager.setDrawable(drawingParams, folderItems[3])
|
||||
@@ -204,7 +206,7 @@ class PreviewItemManagerTest {
|
||||
|
||||
@Test
|
||||
fun checkUnthemedIconWithBadgeWithThemingOff_iconAndBadgeShouldNotBeThemed() {
|
||||
get(context).put(THEMED_ICONS, false)
|
||||
themeManager.isMonoThemeEnabled = false
|
||||
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
|
||||
|
||||
previewItemManager.setDrawable(drawingParams, folderItems[3])
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.graphics
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.launcher3.FakeLauncherPrefs
|
||||
import com.android.launcher3.dagger.LauncherAppComponent
|
||||
import com.android.launcher3.dagger.LauncherAppModule
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
|
||||
import com.android.launcher3.util.SandboxApplication
|
||||
import com.android.launcher3.util.TestUtil
|
||||
import dagger.Component
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ThemeManagerTest {
|
||||
|
||||
@get:Rule val context = SandboxApplication()
|
||||
|
||||
lateinit var themeManager: ThemeManager
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
context.initDaggerComponent(DaggerThemeManagerComponent.builder())
|
||||
themeManager = ThemeManager.INSTANCE[context]
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isMonoThemeEnabled get and set`() {
|
||||
themeManager.isMonoThemeEnabled = true
|
||||
TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {}
|
||||
assertTrue(themeManager.isMonoThemeEnabled)
|
||||
assertTrue(themeManager.iconState.isMonoTheme)
|
||||
|
||||
themeManager.isMonoThemeEnabled = false
|
||||
TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {}
|
||||
assertFalse(themeManager.isMonoThemeEnabled)
|
||||
assertFalse(themeManager.iconState.isMonoTheme)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `callback called on theme change`() {
|
||||
themeManager.isMonoThemeEnabled = false
|
||||
|
||||
var callbackCalled = false
|
||||
themeManager.addChangeListener { callbackCalled = true }
|
||||
themeManager.isMonoThemeEnabled = true
|
||||
TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {}
|
||||
|
||||
assertTrue(callbackCalled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iconState changes with theme`() {
|
||||
themeManager.isMonoThemeEnabled = false
|
||||
TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {}
|
||||
val disabledIconState = themeManager.iconState
|
||||
|
||||
themeManager.isMonoThemeEnabled = true
|
||||
TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {}
|
||||
assertNotEquals(disabledIconState, themeManager.iconState)
|
||||
|
||||
themeManager.isMonoThemeEnabled = false
|
||||
TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {}
|
||||
assertEquals(disabledIconState, themeManager.iconState)
|
||||
}
|
||||
}
|
||||
|
||||
@LauncherAppSingleton
|
||||
@Component(modules = [LauncherAppModule::class])
|
||||
interface ThemeManagerComponent : LauncherAppComponent {
|
||||
|
||||
override fun getLauncherPrefs(): FakeLauncherPrefs
|
||||
|
||||
@Component.Builder
|
||||
interface Builder : LauncherAppComponent.Builder {
|
||||
|
||||
override fun build(): ThemeManagerComponent
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user