Fix LauncherPrefs crash by allowing sub-types of Set

Bug: 396616795
Test: LauncherPrefsTest
Flag: EXEMPT bugfix
Change-Id: Id380a6e4bb5eb809978070ff1b523c9e98e6b869
This commit is contained in:
Charlie Anderson
2025-02-28 21:57:43 +00:00
parent 8bc3268ec4
commit 4e4ad89696
2 changed files with 66 additions and 25 deletions
+24 -23
View File
@@ -75,18 +75,18 @@ constructor(@ApplicationContext private val encryptedContext: Context) {
@Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST")
private fun <T> 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<String>)
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<String>)
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<String>)
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<String>)
else ->
throw IllegalArgumentException(
"item type: ${item.type} is not compatible with sharedPref methods"
@@ -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<String>())
private val TEST_HASHSET_ITEM = LauncherPrefs.nonRestorableItem("7", hashSetOf<String>())
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<String, String>())
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)
}
}