Loading quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ 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.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_DISABLED; Loading @@ -39,6 +40,7 @@ import android.util.Log; import android.util.Xml; import com.android.launcher3.AutoInstallsLayout; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.StatsLogManager; Loading Loading @@ -178,7 +180,7 @@ public class SettingsChangeLogger implements logger::log); SharedPreferences prefs = getPrefs(mContext); logger.log(prefs.getBoolean(KEY_THEMED_ICONS, false) logger.log(LauncherPrefs.get(mContext).get(THEMED_ICONS) ? LAUNCHER_THEMED_ICON_ENABLED : LAUNCHER_THEMED_ICON_DISABLED); Loading src/com/android/launcher3/LauncherAppState.java +7 −7 Original line number Diff line number Diff line Loading @@ -18,7 +18,8 @@ package com.android.launcher3; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED; import static com.android.launcher3.LauncherPrefs.getDevicePrefs; import static com.android.launcher3.LauncherPrefs.ICON_STATE; import static com.android.launcher3.LauncherPrefs.THEMED_ICONS; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI; Loading Loading @@ -55,7 +56,7 @@ import com.android.launcher3.widget.custom.CustomWidgetManager; public class LauncherAppState implements SafeCloseable { public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher"; private static final String KEY_ICON_STATE = "pref_icon_shape_path"; public static final String KEY_ICON_STATE = "pref_icon_shape_path"; // We do not need any synchronization for this variable as its only written on UI thread. public static final MainThreadInitializedObject<LauncherAppState> INSTANCE = Loading Loading @@ -117,10 +118,9 @@ public class LauncherAppState implements SafeCloseable { observer, MODEL_EXECUTOR.getHandler()); mOnTerminateCallback.add(iconChangeTracker::close); MODEL_EXECUTOR.execute(observer::verifyIconChanged); SharedPreferences prefs = LauncherPrefs.getPrefs(mContext); prefs.registerOnSharedPreferenceChangeListener(observer); LauncherPrefs.get(context).addListener(observer, THEMED_ICONS); mOnTerminateCallback.add( () -> prefs.unregisterOnSharedPreferenceChangeListener(observer)); () -> LauncherPrefs.get(mContext).removeListener(observer, THEMED_ICONS)); InstallSessionTracker installSessionTracker = InstallSessionHelper.INSTANCE.get(context).registerInstallTracker(mModel); Loading Loading @@ -207,12 +207,12 @@ public class LauncherAppState implements SafeCloseable { public void onSystemIconStateChanged(String iconState) { IconShape.init(mContext); refreshAndReloadLauncher(); getDevicePrefs(mContext).edit().putString(KEY_ICON_STATE, iconState).apply(); LauncherPrefs.get(mContext).put(ICON_STATE, iconState); } void verifyIconChanged() { String iconState = mIconProvider.getSystemIconState(); if (!iconState.equals(getDevicePrefs(mContext).getString(KEY_ICON_STATE, ""))) { if (!iconState.equals(LauncherPrefs.get(mContext).get(ICON_STATE))) { onSystemIconStateChanged(iconState); } } Loading src/com/android/launcher3/LauncherPrefs.kt +246 −15 Original line number Diff line number Diff line Loading @@ -2,24 +2,255 @@ package com.android.launcher3 import android.content.Context import android.content.SharedPreferences import android.content.SharedPreferences.OnSharedPreferenceChangeListener import androidx.annotation.VisibleForTesting import com.android.launcher3.allapps.WorkProfileManager import com.android.launcher3.model.DeviceGridState import com.android.launcher3.pm.InstallSessionHelper import com.android.launcher3.provider.RestoreDbTask import com.android.launcher3.util.MainThreadInitializedObject import com.android.launcher3.util.Themes object LauncherPrefs { /** * Use same context for shared preferences, so that we use a single cached instance * TODO(b/262721340): Replace all direct SharedPreference refs with LauncherPrefs / Item methods. */ class LauncherPrefs(private val context: Context) { /** * Retrieves the value for an [Item] from [SharedPreferences]. It handles method typing via the * default value type, and will throw an error if the type of the item provided is not a * `String`, `Boolean`, `Float`, `Int`, `Long`, or `Set<String>`. */ @Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST") fun <T : Any> get(item: Item<T>): T { val sp = context.getSharedPreferences(item.sharedPrefFile, Context.MODE_PRIVATE) return when (item.defaultValue::class.java) { String::class.java -> sp.getString(item.sharedPrefKey, item.defaultValue as String) Boolean::class.java, java.lang.Boolean::class.java -> sp.getBoolean(item.sharedPrefKey, item.defaultValue as Boolean) Int::class.java, java.lang.Integer::class.java -> sp.getInt(item.sharedPrefKey, item.defaultValue as Int) Float::class.java, java.lang.Float::class.java -> sp.getFloat(item.sharedPrefKey, item.defaultValue as Float) Long::class.java, java.lang.Long::class.java -> sp.getLong(item.sharedPrefKey, item.defaultValue as Long) Set::class.java -> sp.getStringSet(item.sharedPrefKey, item.defaultValue as Set<String>) else -> throw IllegalArgumentException( "item type: ${item.defaultValue::class.java}" + " is not compatible with sharedPref methods" ) } as T } /** * Stores each of the values provided in `SharedPreferences` according to the configuration * contained within the associated items provided. Internally, it uses apply, so the caller * cannot assume that the values that have been put are immediately available for use. * * The forEach loop is necessary here since there is 1 `SharedPreference.Editor` returned from * prepareToPutValue(itemsToValues) for every distinct `SharedPreferences` file present in the * provided item configurations. */ fun put(vararg itemsToValues: Pair<Item<*>, Any>): Unit = prepareToPutValues(itemsToValues).forEach { it.apply() } /** * Stores the value provided in `SharedPreferences` according to the item configuration provided * It is asynchronous, so the caller can't assume that the value put is immediately available. */ fun <T : Any> put(item: Item<T>, value: T): Unit = context .getSharedPreferences(item.sharedPrefFile, Context.MODE_PRIVATE) .edit() .putValue(item, value) .apply() /** * Synchronously stores all the values provided according to their associated Item * configuration. */ fun putSync(vararg itemsToValues: Pair<Item<*>, Any>): Unit = prepareToPutValues(itemsToValues).forEach { it.commit() } /** * Update each shared preference file with the item - value pairs provided. This method is * optimized to avoid retrieving the same shared preference file multiple times. * * @return `List<SharedPreferences.Editor>` 1 for each distinct shared preference file among the * items given as part of the itemsToValues parameter */ private fun prepareToPutValues( itemsToValues: Array<out Pair<Item<*>, Any>> ): List<SharedPreferences.Editor> = itemsToValues .groupBy { it.first.sharedPrefFile } .map { fileToItemValueList -> context .getSharedPreferences(fileToItemValueList.key, Context.MODE_PRIVATE) .edit() .apply { fileToItemValueList.value.forEach { itemToValue -> putValue(itemToValue.first, itemToValue.second) } } } /** * Handles adding values to `SharedPreferences` regardless of type. This method is especially * helpful for updating `SharedPreferences` values for `List<<Item>Any>` that have multiple * types of Item values. */ @Suppress("UNCHECKED_CAST") private fun SharedPreferences.Editor.putValue( item: Item<*>, value: Any ): SharedPreferences.Editor = when (value::class.java) { String::class.java -> putString(item.sharedPrefKey, value as String) Boolean::class.java, java.lang.Boolean::class.java -> putBoolean(item.sharedPrefKey, value as Boolean) Int::class.java, java.lang.Integer::class.java -> putInt(item.sharedPrefKey, value as Int) Float::class.java, java.lang.Float::class.java -> putFloat(item.sharedPrefKey, value as Float) Long::class.java, java.lang.Long::class.java -> putLong(item.sharedPrefKey, value as Long) Set::class.java -> putStringSet(item.sharedPrefKey, value as Set<String>) else -> throw IllegalArgumentException( "item type: " + "${item.defaultValue!!::class} is not compatible with sharedPref methods" ) } /** * After calling this method, the listener will be notified of any future updates to the * `SharedPreferences` files associated with the provided list of items. The listener will need * to filter update notifications so they don't activate for non-relevant updates. */ fun addListener(listener: OnSharedPreferenceChangeListener, vararg items: Item<*>) { items .map { it.sharedPrefFile } .distinct() .forEach { context .getSharedPreferences(it, Context.MODE_PRIVATE) .registerOnSharedPreferenceChangeListener(listener) } } /** * Stops the listener from getting notified of any more updates to any of the * `SharedPreferences` files associated with any of the provided list of [Item]. */ fun removeListener(listener: OnSharedPreferenceChangeListener, vararg items: Item<*>) { // If a listener is not registered to a SharedPreference, unregistering it does nothing items .map { it.sharedPrefFile } .distinct() .forEach { context .getSharedPreferences(it, Context.MODE_PRIVATE) .unregisterOnSharedPreferenceChangeListener(listener) } } /** * Checks if all the provided [Item] have values stored in their corresponding * `SharedPreferences` files. */ fun has(vararg items: Item<*>): Boolean { items .groupBy { it.sharedPrefFile } .forEach { (file, itemsSublist) -> val prefs: SharedPreferences = context.getSharedPreferences(file, Context.MODE_PRIVATE) if (!itemsSublist.none { !prefs.contains(it.sharedPrefKey) }) return false } return true } /** * Asynchronously removes the [Item]'s value from its corresponding `SharedPreferences` file. */ fun remove(vararg items: Item<*>) = prepareToRemove(items).forEach { it.apply() } /** Synchronously removes the [Item]'s value from its corresponding `SharedPreferences` file. */ fun removeSync(vararg items: Item<*>) = prepareToRemove(items).forEach { it.commit() } /** * Creates `SharedPreferences.Editor` transactions for removing all the provided [Item] values * from their respective `SharedPreferences` files. These returned `Editors` can then be * committed or applied for synchronous or async behavior. */ private fun prepareToRemove(items: Array<out Item<*>>): List<SharedPreferences.Editor> = items .groupBy { it.sharedPrefFile } .map { (file, items) -> context.getSharedPreferences(file, Context.MODE_PRIVATE).edit().also { editor -> items.forEach { item -> editor.remove(item.sharedPrefKey) } } } companion object { @JvmField var INSTANCE = MainThreadInitializedObject { LauncherPrefs(it) } @JvmStatic fun get(context: Context): LauncherPrefs = INSTANCE.get(context) @JvmField val ICON_STATE = nonRestorableItem(LauncherAppState.KEY_ICON_STATE, "") @JvmField val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false) @JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "") @JvmField val WORK_EDU_STEP = backedUpItem(WorkProfileManager.KEY_WORK_EDU_STEP, 0) @JvmField val WORKSPACE_SIZE = backedUpItem(DeviceGridState.KEY_WORKSPACE_SIZE, "") @JvmField val HOTSEAT_COUNT = backedUpItem(DeviceGridState.KEY_HOTSEAT_COUNT, -1) @JvmField val DEVICE_TYPE = backedUpItem(DeviceGridState.KEY_DEVICE_TYPE, InvariantDeviceProfile.TYPE_PHONE) @JvmField val DB_FILE = backedUpItem(DeviceGridState.KEY_DB_FILE, "") @JvmField val RESTORE_DEVICE = backedUpItem(RestoreDbTask.RESTORED_DEVICE_TYPE, InvariantDeviceProfile.TYPE_PHONE) @JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "") @JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "") @VisibleForTesting @JvmStatic fun <T> backedUpItem(sharedPrefKey: String, defaultValue: T): Item<T> = Item(sharedPrefKey, LauncherFiles.SHARED_PREFERENCES_KEY, defaultValue) @VisibleForTesting @JvmStatic fun <T> nonRestorableItem(sharedPrefKey: String, defaultValue: T): Item<T> = Item(sharedPrefKey, LauncherFiles.DEVICE_PREFERENCES_KEY, defaultValue) @Deprecated("Don't use shared preferences directly. Use other LauncherPref methods.") @JvmStatic fun getPrefs(context: Context): SharedPreferences { // Use application context for shared preferences, so that we use a single cached instance // Use application context for shared preferences, so we use single cached instance return context.applicationContext.getSharedPreferences( LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE ) } @Deprecated("Don't use shared preferences directly. Use other LauncherPref methods.") @JvmStatic fun getDevicePrefs(context: Context): SharedPreferences { // Use application context for shared preferences, so that we use a single cached instance // Use application context for shared preferences, so we use a single cached instance return context.applicationContext.getSharedPreferences( LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE ) } } } data class Item<T>(val sharedPrefKey: String, val sharedPrefFile: String, val defaultValue: T) { fun to(value: T): Pair<Item<T>, T> = Pair(this, value) } src/com/android/launcher3/allapps/BaseAllAppsContainerView.java +2 −5 Original line number Diff line number Diff line Loading @@ -57,7 +57,6 @@ import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.Insettable; import com.android.launcher3.InsettableFrameLayout; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider; Loading Loading @@ -161,10 +160,8 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte R.dimen.dynamic_grid_cell_border_spacing); mHeaderProtectionColor = Themes.getAttrColor(context, R.attr.allappsHeaderProtectionColor); mWorkManager = new WorkProfileManager( mActivityContext.getSystemService(UserManager.class), this, LauncherPrefs.getPrefs(mActivityContext), mActivityContext.getStatsLogManager()); mWorkManager = new WorkProfileManager(mActivityContext.getSystemService(UserManager.class), this, mActivityContext.getStatsLogManager()); mAH = Arrays.asList(null, null, null); mNavBarScrimPaint = new Paint(); mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor)); Loading src/com/android/launcher3/allapps/WorkEduCard.java +2 −2 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.launcher3.allapps; import static com.android.launcher3.LauncherPrefs.WORK_EDU_STEP; import static com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.getTabWidth; import android.content.Context; Loading Loading @@ -85,8 +86,7 @@ public class WorkEduCard extends FrameLayout implements @Override public void onClick(View view) { startAnimation(mDismissAnim); LauncherPrefs.getPrefs(getContext()).edit().putInt(WorkProfileManager.KEY_WORK_EDU_STEP, 1).apply(); LauncherPrefs.get(getContext()).put(WORK_EDU_STEP, 1); } @Override Loading Loading
quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ 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.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_DISABLED; Loading @@ -39,6 +40,7 @@ import android.util.Log; import android.util.Xml; import com.android.launcher3.AutoInstallsLayout; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.StatsLogManager; Loading Loading @@ -178,7 +180,7 @@ public class SettingsChangeLogger implements logger::log); SharedPreferences prefs = getPrefs(mContext); logger.log(prefs.getBoolean(KEY_THEMED_ICONS, false) logger.log(LauncherPrefs.get(mContext).get(THEMED_ICONS) ? LAUNCHER_THEMED_ICON_ENABLED : LAUNCHER_THEMED_ICON_DISABLED); Loading
src/com/android/launcher3/LauncherAppState.java +7 −7 Original line number Diff line number Diff line Loading @@ -18,7 +18,8 @@ package com.android.launcher3; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED; import static com.android.launcher3.LauncherPrefs.getDevicePrefs; import static com.android.launcher3.LauncherPrefs.ICON_STATE; import static com.android.launcher3.LauncherPrefs.THEMED_ICONS; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI; Loading Loading @@ -55,7 +56,7 @@ import com.android.launcher3.widget.custom.CustomWidgetManager; public class LauncherAppState implements SafeCloseable { public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher"; private static final String KEY_ICON_STATE = "pref_icon_shape_path"; public static final String KEY_ICON_STATE = "pref_icon_shape_path"; // We do not need any synchronization for this variable as its only written on UI thread. public static final MainThreadInitializedObject<LauncherAppState> INSTANCE = Loading Loading @@ -117,10 +118,9 @@ public class LauncherAppState implements SafeCloseable { observer, MODEL_EXECUTOR.getHandler()); mOnTerminateCallback.add(iconChangeTracker::close); MODEL_EXECUTOR.execute(observer::verifyIconChanged); SharedPreferences prefs = LauncherPrefs.getPrefs(mContext); prefs.registerOnSharedPreferenceChangeListener(observer); LauncherPrefs.get(context).addListener(observer, THEMED_ICONS); mOnTerminateCallback.add( () -> prefs.unregisterOnSharedPreferenceChangeListener(observer)); () -> LauncherPrefs.get(mContext).removeListener(observer, THEMED_ICONS)); InstallSessionTracker installSessionTracker = InstallSessionHelper.INSTANCE.get(context).registerInstallTracker(mModel); Loading Loading @@ -207,12 +207,12 @@ public class LauncherAppState implements SafeCloseable { public void onSystemIconStateChanged(String iconState) { IconShape.init(mContext); refreshAndReloadLauncher(); getDevicePrefs(mContext).edit().putString(KEY_ICON_STATE, iconState).apply(); LauncherPrefs.get(mContext).put(ICON_STATE, iconState); } void verifyIconChanged() { String iconState = mIconProvider.getSystemIconState(); if (!iconState.equals(getDevicePrefs(mContext).getString(KEY_ICON_STATE, ""))) { if (!iconState.equals(LauncherPrefs.get(mContext).get(ICON_STATE))) { onSystemIconStateChanged(iconState); } } Loading
src/com/android/launcher3/LauncherPrefs.kt +246 −15 Original line number Diff line number Diff line Loading @@ -2,24 +2,255 @@ package com.android.launcher3 import android.content.Context import android.content.SharedPreferences import android.content.SharedPreferences.OnSharedPreferenceChangeListener import androidx.annotation.VisibleForTesting import com.android.launcher3.allapps.WorkProfileManager import com.android.launcher3.model.DeviceGridState import com.android.launcher3.pm.InstallSessionHelper import com.android.launcher3.provider.RestoreDbTask import com.android.launcher3.util.MainThreadInitializedObject import com.android.launcher3.util.Themes object LauncherPrefs { /** * Use same context for shared preferences, so that we use a single cached instance * TODO(b/262721340): Replace all direct SharedPreference refs with LauncherPrefs / Item methods. */ class LauncherPrefs(private val context: Context) { /** * Retrieves the value for an [Item] from [SharedPreferences]. It handles method typing via the * default value type, and will throw an error if the type of the item provided is not a * `String`, `Boolean`, `Float`, `Int`, `Long`, or `Set<String>`. */ @Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST") fun <T : Any> get(item: Item<T>): T { val sp = context.getSharedPreferences(item.sharedPrefFile, Context.MODE_PRIVATE) return when (item.defaultValue::class.java) { String::class.java -> sp.getString(item.sharedPrefKey, item.defaultValue as String) Boolean::class.java, java.lang.Boolean::class.java -> sp.getBoolean(item.sharedPrefKey, item.defaultValue as Boolean) Int::class.java, java.lang.Integer::class.java -> sp.getInt(item.sharedPrefKey, item.defaultValue as Int) Float::class.java, java.lang.Float::class.java -> sp.getFloat(item.sharedPrefKey, item.defaultValue as Float) Long::class.java, java.lang.Long::class.java -> sp.getLong(item.sharedPrefKey, item.defaultValue as Long) Set::class.java -> sp.getStringSet(item.sharedPrefKey, item.defaultValue as Set<String>) else -> throw IllegalArgumentException( "item type: ${item.defaultValue::class.java}" + " is not compatible with sharedPref methods" ) } as T } /** * Stores each of the values provided in `SharedPreferences` according to the configuration * contained within the associated items provided. Internally, it uses apply, so the caller * cannot assume that the values that have been put are immediately available for use. * * The forEach loop is necessary here since there is 1 `SharedPreference.Editor` returned from * prepareToPutValue(itemsToValues) for every distinct `SharedPreferences` file present in the * provided item configurations. */ fun put(vararg itemsToValues: Pair<Item<*>, Any>): Unit = prepareToPutValues(itemsToValues).forEach { it.apply() } /** * Stores the value provided in `SharedPreferences` according to the item configuration provided * It is asynchronous, so the caller can't assume that the value put is immediately available. */ fun <T : Any> put(item: Item<T>, value: T): Unit = context .getSharedPreferences(item.sharedPrefFile, Context.MODE_PRIVATE) .edit() .putValue(item, value) .apply() /** * Synchronously stores all the values provided according to their associated Item * configuration. */ fun putSync(vararg itemsToValues: Pair<Item<*>, Any>): Unit = prepareToPutValues(itemsToValues).forEach { it.commit() } /** * Update each shared preference file with the item - value pairs provided. This method is * optimized to avoid retrieving the same shared preference file multiple times. * * @return `List<SharedPreferences.Editor>` 1 for each distinct shared preference file among the * items given as part of the itemsToValues parameter */ private fun prepareToPutValues( itemsToValues: Array<out Pair<Item<*>, Any>> ): List<SharedPreferences.Editor> = itemsToValues .groupBy { it.first.sharedPrefFile } .map { fileToItemValueList -> context .getSharedPreferences(fileToItemValueList.key, Context.MODE_PRIVATE) .edit() .apply { fileToItemValueList.value.forEach { itemToValue -> putValue(itemToValue.first, itemToValue.second) } } } /** * Handles adding values to `SharedPreferences` regardless of type. This method is especially * helpful for updating `SharedPreferences` values for `List<<Item>Any>` that have multiple * types of Item values. */ @Suppress("UNCHECKED_CAST") private fun SharedPreferences.Editor.putValue( item: Item<*>, value: Any ): SharedPreferences.Editor = when (value::class.java) { String::class.java -> putString(item.sharedPrefKey, value as String) Boolean::class.java, java.lang.Boolean::class.java -> putBoolean(item.sharedPrefKey, value as Boolean) Int::class.java, java.lang.Integer::class.java -> putInt(item.sharedPrefKey, value as Int) Float::class.java, java.lang.Float::class.java -> putFloat(item.sharedPrefKey, value as Float) Long::class.java, java.lang.Long::class.java -> putLong(item.sharedPrefKey, value as Long) Set::class.java -> putStringSet(item.sharedPrefKey, value as Set<String>) else -> throw IllegalArgumentException( "item type: " + "${item.defaultValue!!::class} is not compatible with sharedPref methods" ) } /** * After calling this method, the listener will be notified of any future updates to the * `SharedPreferences` files associated with the provided list of items. The listener will need * to filter update notifications so they don't activate for non-relevant updates. */ fun addListener(listener: OnSharedPreferenceChangeListener, vararg items: Item<*>) { items .map { it.sharedPrefFile } .distinct() .forEach { context .getSharedPreferences(it, Context.MODE_PRIVATE) .registerOnSharedPreferenceChangeListener(listener) } } /** * Stops the listener from getting notified of any more updates to any of the * `SharedPreferences` files associated with any of the provided list of [Item]. */ fun removeListener(listener: OnSharedPreferenceChangeListener, vararg items: Item<*>) { // If a listener is not registered to a SharedPreference, unregistering it does nothing items .map { it.sharedPrefFile } .distinct() .forEach { context .getSharedPreferences(it, Context.MODE_PRIVATE) .unregisterOnSharedPreferenceChangeListener(listener) } } /** * Checks if all the provided [Item] have values stored in their corresponding * `SharedPreferences` files. */ fun has(vararg items: Item<*>): Boolean { items .groupBy { it.sharedPrefFile } .forEach { (file, itemsSublist) -> val prefs: SharedPreferences = context.getSharedPreferences(file, Context.MODE_PRIVATE) if (!itemsSublist.none { !prefs.contains(it.sharedPrefKey) }) return false } return true } /** * Asynchronously removes the [Item]'s value from its corresponding `SharedPreferences` file. */ fun remove(vararg items: Item<*>) = prepareToRemove(items).forEach { it.apply() } /** Synchronously removes the [Item]'s value from its corresponding `SharedPreferences` file. */ fun removeSync(vararg items: Item<*>) = prepareToRemove(items).forEach { it.commit() } /** * Creates `SharedPreferences.Editor` transactions for removing all the provided [Item] values * from their respective `SharedPreferences` files. These returned `Editors` can then be * committed or applied for synchronous or async behavior. */ private fun prepareToRemove(items: Array<out Item<*>>): List<SharedPreferences.Editor> = items .groupBy { it.sharedPrefFile } .map { (file, items) -> context.getSharedPreferences(file, Context.MODE_PRIVATE).edit().also { editor -> items.forEach { item -> editor.remove(item.sharedPrefKey) } } } companion object { @JvmField var INSTANCE = MainThreadInitializedObject { LauncherPrefs(it) } @JvmStatic fun get(context: Context): LauncherPrefs = INSTANCE.get(context) @JvmField val ICON_STATE = nonRestorableItem(LauncherAppState.KEY_ICON_STATE, "") @JvmField val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false) @JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "") @JvmField val WORK_EDU_STEP = backedUpItem(WorkProfileManager.KEY_WORK_EDU_STEP, 0) @JvmField val WORKSPACE_SIZE = backedUpItem(DeviceGridState.KEY_WORKSPACE_SIZE, "") @JvmField val HOTSEAT_COUNT = backedUpItem(DeviceGridState.KEY_HOTSEAT_COUNT, -1) @JvmField val DEVICE_TYPE = backedUpItem(DeviceGridState.KEY_DEVICE_TYPE, InvariantDeviceProfile.TYPE_PHONE) @JvmField val DB_FILE = backedUpItem(DeviceGridState.KEY_DB_FILE, "") @JvmField val RESTORE_DEVICE = backedUpItem(RestoreDbTask.RESTORED_DEVICE_TYPE, InvariantDeviceProfile.TYPE_PHONE) @JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "") @JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "") @VisibleForTesting @JvmStatic fun <T> backedUpItem(sharedPrefKey: String, defaultValue: T): Item<T> = Item(sharedPrefKey, LauncherFiles.SHARED_PREFERENCES_KEY, defaultValue) @VisibleForTesting @JvmStatic fun <T> nonRestorableItem(sharedPrefKey: String, defaultValue: T): Item<T> = Item(sharedPrefKey, LauncherFiles.DEVICE_PREFERENCES_KEY, defaultValue) @Deprecated("Don't use shared preferences directly. Use other LauncherPref methods.") @JvmStatic fun getPrefs(context: Context): SharedPreferences { // Use application context for shared preferences, so that we use a single cached instance // Use application context for shared preferences, so we use single cached instance return context.applicationContext.getSharedPreferences( LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE ) } @Deprecated("Don't use shared preferences directly. Use other LauncherPref methods.") @JvmStatic fun getDevicePrefs(context: Context): SharedPreferences { // Use application context for shared preferences, so that we use a single cached instance // Use application context for shared preferences, so we use a single cached instance return context.applicationContext.getSharedPreferences( LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE ) } } } data class Item<T>(val sharedPrefKey: String, val sharedPrefFile: String, val defaultValue: T) { fun to(value: T): Pair<Item<T>, T> = Pair(this, value) }
src/com/android/launcher3/allapps/BaseAllAppsContainerView.java +2 −5 Original line number Diff line number Diff line Loading @@ -57,7 +57,6 @@ import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.Insettable; import com.android.launcher3.InsettableFrameLayout; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider; Loading Loading @@ -161,10 +160,8 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte R.dimen.dynamic_grid_cell_border_spacing); mHeaderProtectionColor = Themes.getAttrColor(context, R.attr.allappsHeaderProtectionColor); mWorkManager = new WorkProfileManager( mActivityContext.getSystemService(UserManager.class), this, LauncherPrefs.getPrefs(mActivityContext), mActivityContext.getStatsLogManager()); mWorkManager = new WorkProfileManager(mActivityContext.getSystemService(UserManager.class), this, mActivityContext.getStatsLogManager()); mAH = Arrays.asList(null, null, null); mNavBarScrimPaint = new Paint(); mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor)); Loading
src/com/android/launcher3/allapps/WorkEduCard.java +2 −2 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.launcher3.allapps; import static com.android.launcher3.LauncherPrefs.WORK_EDU_STEP; import static com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.getTabWidth; import android.content.Context; Loading Loading @@ -85,8 +86,7 @@ public class WorkEduCard extends FrameLayout implements @Override public void onClick(View view) { startAnimation(mDismissAnim); LauncherPrefs.getPrefs(getContext()).edit().putInt(WorkProfileManager.KEY_WORK_EDU_STEP, 1).apply(); LauncherPrefs.get(getContext()).put(WORK_EDU_STEP, 1); } @Override Loading