332 lines
12 KiB
Kotlin
332 lines
12 KiB
Kotlin
|
/*
|
||
|
* Copyright (C) 2023 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
|
||
|
|
||
|
import android.content.Context
|
||
|
import android.content.SharedPreferences
|
||
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||
|
import androidx.test.filters.SmallTest
|
||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||
|
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.AfterClass
|
||
|
import org.junit.BeforeClass
|
||
|
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_CONTEXTUAL_ITEM = ContextualItem("4", true, { true }, false, Boolean::class.java)
|
||
|
|
||
|
private const val TEST_DEFAULT_VALUE = "default"
|
||
|
private const val TEST_PREF_KEY = "test_pref_key"
|
||
|
|
||
|
private const val WAIT_TIME_IN_SECONDS = 3L
|
||
|
|
||
|
@SmallTest
|
||
|
@RunWith(AndroidJUnit4::class)
|
||
|
class LauncherPrefsTest {
|
||
|
|
||
|
private val context by lazy { InstrumentationRegistry.getInstrumentation().targetContext }
|
||
|
private val launcherPrefs by lazy { LauncherPrefs.get(context) }
|
||
|
|
||
|
companion object {
|
||
|
@BeforeClass
|
||
|
@JvmStatic
|
||
|
fun setup() {
|
||
|
isBootAwareStartupDataEnabled = true
|
||
|
}
|
||
|
|
||
|
@AfterClass
|
||
|
@JvmStatic
|
||
|
fun teardown() {
|
||
|
isBootAwareStartupDataEnabled = false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun has_keyMissingFromLauncherPrefs_returnsFalse() {
|
||
|
assertThat(launcherPrefs.has(TEST_BOOLEAN_ITEM)).isFalse()
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun has_keyPresentInLauncherPrefs_returnsTrue() {
|
||
|
with(launcherPrefs) {
|
||
|
putSync(TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue))
|
||
|
assertThat(has(TEST_BOOLEAN_ITEM)).isTrue()
|
||
|
remove(TEST_BOOLEAN_ITEM)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun addListener_listeningForStringItemUpdates_isCorrectlyNotifiedOfUpdates() {
|
||
|
val latch = CountDownLatch(1)
|
||
|
val listener = OnSharedPreferenceChangeListener { _, _ -> latch.countDown() }
|
||
|
|
||
|
with(launcherPrefs) {
|
||
|
putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue))
|
||
|
addListener(listener, TEST_STRING_ITEM)
|
||
|
putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "abc"))
|
||
|
|
||
|
assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isTrue()
|
||
|
remove(TEST_STRING_ITEM)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun removeListener_previouslyListeningForStringItemUpdates_isNoLongerNotifiedOfUpdates() {
|
||
|
val latch = CountDownLatch(1)
|
||
|
val listener = OnSharedPreferenceChangeListener { _, _ -> latch.countDown() }
|
||
|
|
||
|
with(launcherPrefs) {
|
||
|
addListener(listener, TEST_STRING_ITEM)
|
||
|
removeListener(listener, TEST_STRING_ITEM)
|
||
|
putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "hello."))
|
||
|
|
||
|
// latch will be still be 1 (and await will return false) if the listener was not called
|
||
|
assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isFalse()
|
||
|
remove(TEST_STRING_ITEM)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun addListenerAndRemoveListener_forMultipleItems_bothWorkProperly() {
|
||
|
var latch = CountDownLatch(3)
|
||
|
val listener = OnSharedPreferenceChangeListener { _, _ -> latch.countDown() }
|
||
|
|
||
|
with(launcherPrefs) {
|
||
|
addListener(listener, TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM)
|
||
|
putSync(
|
||
|
TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue + 123),
|
||
|
TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "abc"),
|
||
|
TEST_BOOLEAN_ITEM.to(!TEST_BOOLEAN_ITEM.defaultValue)
|
||
|
)
|
||
|
assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isTrue()
|
||
|
|
||
|
removeListener(listener, TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM)
|
||
|
latch = CountDownLatch(1)
|
||
|
putSync(
|
||
|
TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue),
|
||
|
TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue),
|
||
|
TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue)
|
||
|
)
|
||
|
remove(TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM)
|
||
|
|
||
|
assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isFalse()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun get_booleanItemNotInLauncherprefs_returnsDefaultValue() {
|
||
|
assertThat(launcherPrefs.get(TEST_BOOLEAN_ITEM)).isEqualTo(TEST_BOOLEAN_ITEM.defaultValue)
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun get_stringItemNotInLauncherPrefs_returnsDefaultValue() {
|
||
|
assertThat(launcherPrefs.get(TEST_STRING_ITEM)).isEqualTo(TEST_STRING_ITEM.defaultValue)
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun get_intItemNotInLauncherprefs_returnsDefaultValue() {
|
||
|
assertThat(launcherPrefs.get(TEST_INT_ITEM)).isEqualTo(TEST_INT_ITEM.defaultValue)
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun put_storesItemInLauncherPrefs_successfully() {
|
||
|
val notDefaultValue = !TEST_BOOLEAN_ITEM.defaultValue
|
||
|
|
||
|
with(launcherPrefs) {
|
||
|
putSync(TEST_BOOLEAN_ITEM.to(notDefaultValue))
|
||
|
assertThat(get(TEST_BOOLEAN_ITEM)).isEqualTo(notDefaultValue)
|
||
|
remove(TEST_BOOLEAN_ITEM)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun put_storesListOfItemsInLauncherPrefs_successfully() {
|
||
|
with(launcherPrefs) {
|
||
|
putSync(
|
||
|
TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue),
|
||
|
TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue),
|
||
|
TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue)
|
||
|
)
|
||
|
assertThat(has(TEST_BOOLEAN_ITEM, TEST_INT_ITEM, TEST_STRING_ITEM)).isTrue()
|
||
|
remove(TEST_STRING_ITEM, TEST_INT_ITEM, TEST_BOOLEAN_ITEM)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun remove_deletesItemFromLauncherPrefs_successfully() {
|
||
|
val notDefaultValue = !TEST_BOOLEAN_ITEM.defaultValue
|
||
|
|
||
|
with(launcherPrefs) {
|
||
|
putSync(TEST_BOOLEAN_ITEM.to(notDefaultValue))
|
||
|
remove(TEST_BOOLEAN_ITEM)
|
||
|
assertThat(get(TEST_BOOLEAN_ITEM)).isEqualTo(TEST_BOOLEAN_ITEM.defaultValue)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun get_contextualItem_returnsCorrectDefault() {
|
||
|
assertThat(launcherPrefs.get(TEST_CONTEXTUAL_ITEM)).isTrue()
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun getItemSharedPrefFile_forNonRestorableItem_isCorrect() {
|
||
|
val nonRestorableItem = LauncherPrefs.nonRestorableItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE)
|
||
|
assertThat(nonRestorableItem.sharedPrefFile).isEqualTo(LauncherFiles.DEVICE_PREFERENCES_KEY)
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun getItemSharedPrefFile_forBackedUpItem_isCorrect() {
|
||
|
val backedUpItem = LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE)
|
||
|
assertThat(backedUpItem.sharedPrefFile).isEqualTo(LauncherFiles.SHARED_PREFERENCES_KEY)
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun put_bootAwareItem_updatesDeviceProtectedStorage() {
|
||
|
val bootAwareItem =
|
||
|
LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true)
|
||
|
|
||
|
val bootAwarePrefs: SharedPreferences =
|
||
|
context
|
||
|
.createDeviceProtectedStorageContext()
|
||
|
.getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
|
||
|
bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
|
||
|
|
||
|
launcherPrefs.putSync(bootAwareItem.to(bootAwareItem.defaultValue))
|
||
|
assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
|
||
|
|
||
|
launcherPrefs.removeSync(bootAwareItem)
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun put_bootAwareItem_updatesEncryptedStorage() {
|
||
|
val bootAwareItem =
|
||
|
LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true)
|
||
|
|
||
|
val encryptedPrefs: SharedPreferences =
|
||
|
context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
|
||
|
encryptedPrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
|
||
|
|
||
|
launcherPrefs.putSync(bootAwareItem.to(TEST_STRING_ITEM.defaultValue))
|
||
|
assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
|
||
|
|
||
|
launcherPrefs.removeSync(bootAwareItem)
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun remove_bootAwareItem_removesFromDeviceProtectedStorage() {
|
||
|
val bootAwareItem =
|
||
|
LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true)
|
||
|
|
||
|
val bootAwarePrefs: SharedPreferences =
|
||
|
context
|
||
|
.createDeviceProtectedStorageContext()
|
||
|
.getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
|
||
|
|
||
|
bootAwarePrefs
|
||
|
.edit()
|
||
|
.putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
|
||
|
.commit()
|
||
|
|
||
|
launcherPrefs.removeSync(bootAwareItem)
|
||
|
assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun remove_bootAwareItem_removesFromEncryptedStorage() {
|
||
|
val bootAwareItem =
|
||
|
LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true)
|
||
|
|
||
|
val encryptedPrefs: SharedPreferences =
|
||
|
context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
|
||
|
|
||
|
encryptedPrefs
|
||
|
.edit()
|
||
|
.putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
|
||
|
.commit()
|
||
|
|
||
|
launcherPrefs.removeSync(bootAwareItem)
|
||
|
assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun migrate_bootAwareItemsToDeviceProtectedStorage_worksAsIntended() {
|
||
|
val bootAwareItem =
|
||
|
LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true)
|
||
|
launcherPrefs.removeSync(bootAwareItem)
|
||
|
|
||
|
val bootAwarePrefs: SharedPreferences =
|
||
|
context
|
||
|
.createDeviceProtectedStorageContext()
|
||
|
.getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
|
||
|
|
||
|
if (bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)) {
|
||
|
bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
|
||
|
}
|
||
|
|
||
|
val encryptedPrefs: SharedPreferences =
|
||
|
context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
|
||
|
|
||
|
encryptedPrefs
|
||
|
.edit()
|
||
|
.putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
|
||
|
.commit()
|
||
|
|
||
|
launcherPrefs.migrateStartupDataToDeviceProtectedStorage()
|
||
|
assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
|
||
|
|
||
|
launcherPrefs.removeSync(bootAwareItem)
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
fun migrate_onlyEncryptedItemsToDeviceProtectedStorage_doesNotHappen() {
|
||
|
val onlyEncryptedItem =
|
||
|
LauncherPrefs.backedUpItem(
|
||
|
TEST_PREF_KEY + "_",
|
||
|
TEST_DEFAULT_VALUE + "_",
|
||
|
isBootAware = false
|
||
|
)
|
||
|
|
||
|
val bootAwarePrefs: SharedPreferences =
|
||
|
context
|
||
|
.createDeviceProtectedStorageContext()
|
||
|
.getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
|
||
|
|
||
|
if (bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)) {
|
||
|
bootAwarePrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit()
|
||
|
}
|
||
|
|
||
|
val encryptedPrefs: SharedPreferences =
|
||
|
context.getSharedPreferences(onlyEncryptedItem.sharedPrefFile, Context.MODE_PRIVATE)
|
||
|
|
||
|
encryptedPrefs
|
||
|
.edit()
|
||
|
.putString(onlyEncryptedItem.sharedPrefKey, onlyEncryptedItem.defaultValue)
|
||
|
.commit()
|
||
|
|
||
|
launcherPrefs.migrateStartupDataToDeviceProtectedStorage()
|
||
|
assertThat(bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)).isFalse()
|
||
|
|
||
|
encryptedPrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit()
|
||
|
}
|
||
|
}
|