From 4e4ad8969649885ed107e2cd24834d402dc7e6c8 Mon Sep 17 00:00:00 2001 From: Charlie Anderson Date: Fri, 28 Feb 2025 21:38:06 +0000 Subject: [PATCH] Fix LauncherPrefs crash by allowing sub-types of Set Bug: 396616795 Test: LauncherPrefsTest Flag: EXEMPT bugfix Change-Id: Id380a6e4bb5eb809978070ff1b523c9e98e6b869 --- src/com/android/launcher3/LauncherPrefs.kt | 47 ++++++++++--------- .../android/launcher3/LauncherPrefsTest.kt | 44 ++++++++++++++++- 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt index 2a5cd63752..7a04b0f950 100644 --- a/src/com/android/launcher3/LauncherPrefs.kt +++ b/src/com/android/launcher3/LauncherPrefs.kt @@ -75,18 +75,18 @@ constructor(@ApplicationContext private val encryptedContext: Context) { @Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST") private fun getInner(item: Item, default: T): T { val sp = getSharedPrefs(item) - - return when (item.type) { - String::class.java -> sp.getString(item.sharedPrefKey, default as? String) - Boolean::class.java, - java.lang.Boolean::class.java -> sp.getBoolean(item.sharedPrefKey, default as Boolean) - Int::class.java, - java.lang.Integer::class.java -> sp.getInt(item.sharedPrefKey, default as Int) - Float::class.java, - java.lang.Float::class.java -> sp.getFloat(item.sharedPrefKey, default as Float) - Long::class.java, - java.lang.Long::class.java -> sp.getLong(item.sharedPrefKey, default as Long) - Set::class.java -> sp.getStringSet(item.sharedPrefKey, default as? Set) + return when { + item.type == String::class.java -> sp.getString(item.sharedPrefKey, default as? String) + item.type == Boolean::class.java || item.type == java.lang.Boolean::class.java -> + sp.getBoolean(item.sharedPrefKey, default as Boolean) + item.type == Int::class.java || item.type == java.lang.Integer::class.java -> + sp.getInt(item.sharedPrefKey, default as Int) + item.type == Float::class.java || item.type == java.lang.Float::class.java -> + sp.getFloat(item.sharedPrefKey, default as Float) + item.type == Long::class.java || item.type == java.lang.Long::class.java -> + sp.getLong(item.sharedPrefKey, default as Long) + Set::class.java.isAssignableFrom(item.type) -> + sp.getStringSet(item.sharedPrefKey, default as? Set) else -> throw IllegalArgumentException( "item type: ${item.type}" + " is not compatible with sharedPref methods" @@ -147,17 +147,18 @@ constructor(@ApplicationContext private val encryptedContext: Context) { item: Item, value: Any?, ): SharedPreferences.Editor = - when (item.type) { - 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) + when { + item.type == String::class.java -> putString(item.sharedPrefKey, value as? String) + item.type == Boolean::class.java || item.type == java.lang.Boolean::class.java -> + putBoolean(item.sharedPrefKey, value as Boolean) + item.type == Int::class.java || item.type == java.lang.Integer::class.java -> + putInt(item.sharedPrefKey, value as Int) + item.type == Float::class.java || item.type == java.lang.Float::class.java -> + putFloat(item.sharedPrefKey, value as Float) + item.type == Long::class.java || item.type == java.lang.Long::class.java -> + putLong(item.sharedPrefKey, value as Long) + Set::class.java.isAssignableFrom(item.type) -> + putStringSet(item.sharedPrefKey, value as? Set) else -> throw IllegalArgumentException( "item type: ${item.type} is not compatible with sharedPref methods" diff --git a/tests/multivalentTests/src/com/android/launcher3/LauncherPrefsTest.kt b/tests/multivalentTests/src/com/android/launcher3/LauncherPrefsTest.kt index 4aeef2e671..da9cc8635d 100644 --- a/tests/multivalentTests/src/com/android/launcher3/LauncherPrefsTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/LauncherPrefsTest.kt @@ -24,12 +24,18 @@ import com.android.launcher3.LauncherPrefs.Companion.BOOT_AWARE_PREFS_KEY import com.google.common.truth.Truth.assertThat import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit +import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith private val TEST_BOOLEAN_ITEM = LauncherPrefs.nonRestorableItem("1", false) private val TEST_STRING_ITEM = LauncherPrefs.nonRestorableItem("2", "( ͡❛ ͜ʖ ͡❛)") private val TEST_INT_ITEM = LauncherPrefs.nonRestorableItem("3", -1) +private val TEST_FLOAT_ITEM = LauncherPrefs.nonRestorableItem("4", -1f) +private val TEST_LONG_ITEM = LauncherPrefs.nonRestorableItem("5", -1L) +private val TEST_SET_ITEM = LauncherPrefs.nonRestorableItem("6", setOf()) +private val TEST_HASHSET_ITEM = LauncherPrefs.nonRestorableItem("7", hashSetOf()) + private val TEST_CONTEXTUAL_ITEM = ContextualItem("4", true, { true }, EncryptionType.ENCRYPTED, Boolean::class.java) @@ -143,6 +149,17 @@ class LauncherPrefsTest { } } + @Test + fun whenItemType_isInvalid_thenThrowException() { + val badItem = LauncherPrefs.nonRestorableItem("8", mapOf()) + with(launcherPrefs) { + assertThrows(IllegalArgumentException::class.java) { + putSync(badItem.to(badItem.defaultValue)) + } + assertThrows(IllegalArgumentException::class.java) { get(badItem) } + } + } + @Test fun put_storesListOfItemsInLauncherPrefs_successfully() { with(launcherPrefs) { @@ -150,9 +167,32 @@ class LauncherPrefsTest { TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue), TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue), TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue), + TEST_FLOAT_ITEM.to(TEST_FLOAT_ITEM.defaultValue), + TEST_LONG_ITEM.to(TEST_LONG_ITEM.defaultValue), + TEST_SET_ITEM.to(TEST_SET_ITEM.defaultValue), + TEST_HASHSET_ITEM.to(TEST_HASHSET_ITEM.defaultValue), + ) + assertThat( + has( + TEST_STRING_ITEM, + TEST_INT_ITEM, + TEST_BOOLEAN_ITEM, + TEST_FLOAT_ITEM, + TEST_LONG_ITEM, + TEST_SET_ITEM, + TEST_HASHSET_ITEM, + ) + ) + .isTrue() + remove( + TEST_STRING_ITEM, + TEST_INT_ITEM, + TEST_BOOLEAN_ITEM, + TEST_FLOAT_ITEM, + TEST_LONG_ITEM, + TEST_SET_ITEM, + TEST_HASHSET_ITEM, ) - assertThat(has(TEST_BOOLEAN_ITEM, TEST_INT_ITEM, TEST_STRING_ITEM)).isTrue() - remove(TEST_STRING_ITEM, TEST_INT_ITEM, TEST_BOOLEAN_ITEM) } }