1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.launcher3 17 18 import android.content.Context 19 import android.content.SharedPreferences 20 import androidx.test.ext.junit.runners.AndroidJUnit4 21 import androidx.test.filters.SmallTest 22 import androidx.test.platform.app.InstrumentationRegistry 23 import com.android.launcher3.LauncherPrefs.Companion.BOOT_AWARE_PREFS_KEY 24 import com.google.common.truth.Truth.assertThat 25 import java.util.concurrent.CountDownLatch 26 import java.util.concurrent.TimeUnit 27 import org.junit.Assert.assertThrows 28 import org.junit.Test 29 import org.junit.runner.RunWith 30 31 private val TEST_BOOLEAN_ITEM = LauncherPrefs.nonRestorableItem("1", false) 32 private val TEST_STRING_ITEM = LauncherPrefs.nonRestorableItem("2", "( ͡❛ ͜ʖ ͡❛)") 33 private val TEST_INT_ITEM = LauncherPrefs.nonRestorableItem("3", -1) 34 private val TEST_FLOAT_ITEM = LauncherPrefs.nonRestorableItem("4", -1f) 35 private val TEST_LONG_ITEM = LauncherPrefs.nonRestorableItem("5", -1L) 36 private val TEST_SET_ITEM = LauncherPrefs.nonRestorableItem("6", setOf<String>()) 37 private val TEST_HASHSET_ITEM = LauncherPrefs.nonRestorableItem("7", hashSetOf<String>()) 38 39 private val TEST_CONTEXTUAL_ITEM = <lambda>null40 ContextualItem("4", true, { true }, EncryptionType.ENCRYPTED, Boolean::class.java) 41 42 private const val TEST_DEFAULT_VALUE = "default" 43 private const val TEST_PREF_KEY = "test_pref_key" 44 45 private const val WAIT_TIME_IN_SECONDS = 3L 46 47 @SmallTest 48 @RunWith(AndroidJUnit4::class) 49 class LauncherPrefsTest { 50 <lambda>null51 private val context by lazy { InstrumentationRegistry.getInstrumentation().targetContext } <lambda>null52 private val launcherPrefs by lazy { LauncherPrefs.get(context) } 53 54 @Test has_keyMissingFromLauncherPrefs_returnsFalsenull55 fun has_keyMissingFromLauncherPrefs_returnsFalse() { 56 assertThat(launcherPrefs.has(TEST_BOOLEAN_ITEM)).isFalse() 57 } 58 59 @Test has_keyPresentInLauncherPrefs_returnsTruenull60 fun has_keyPresentInLauncherPrefs_returnsTrue() { 61 with(launcherPrefs) { 62 putSync(TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue)) 63 assertThat(has(TEST_BOOLEAN_ITEM)).isTrue() 64 remove(TEST_BOOLEAN_ITEM) 65 } 66 } 67 68 @Test addListener_listeningForStringItemUpdates_isCorrectlyNotifiedOfUpdatesnull69 fun addListener_listeningForStringItemUpdates_isCorrectlyNotifiedOfUpdates() { 70 val latch = CountDownLatch(1) 71 val listener = LauncherPrefChangeListener { latch.countDown() } 72 73 with(launcherPrefs) { 74 putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue)) 75 addListener(listener, TEST_STRING_ITEM) 76 putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "abc")) 77 78 assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isTrue() 79 remove(TEST_STRING_ITEM) 80 } 81 } 82 83 @Test removeListener_previouslyListeningForStringItemUpdates_isNoLongerNotifiedOfUpdatesnull84 fun removeListener_previouslyListeningForStringItemUpdates_isNoLongerNotifiedOfUpdates() { 85 val latch = CountDownLatch(1) 86 val listener = LauncherPrefChangeListener { latch.countDown() } 87 88 with(launcherPrefs) { 89 addListener(listener, TEST_STRING_ITEM) 90 removeListener(listener, TEST_STRING_ITEM) 91 putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "hello.")) 92 93 // latch will be still be 1 (and await will return false) if the listener was not called 94 assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isFalse() 95 remove(TEST_STRING_ITEM) 96 } 97 } 98 99 @Test addListenerAndRemoveListener_forMultipleItems_bothWorkProperlynull100 fun addListenerAndRemoveListener_forMultipleItems_bothWorkProperly() { 101 var latch = CountDownLatch(3) 102 val listener = LauncherPrefChangeListener { latch.countDown() } 103 104 with(launcherPrefs) { 105 addListener(listener, TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM) 106 putSync( 107 TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue + 123), 108 TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "abc"), 109 TEST_BOOLEAN_ITEM.to(!TEST_BOOLEAN_ITEM.defaultValue), 110 ) 111 assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isTrue() 112 113 removeListener(listener, TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM) 114 latch = CountDownLatch(1) 115 putSync( 116 TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue), 117 TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue), 118 TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue), 119 ) 120 remove(TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM) 121 122 assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isFalse() 123 } 124 } 125 126 @Test get_booleanItemNotInLauncherprefs_returnsDefaultValuenull127 fun get_booleanItemNotInLauncherprefs_returnsDefaultValue() { 128 assertThat(launcherPrefs.get(TEST_BOOLEAN_ITEM)).isEqualTo(TEST_BOOLEAN_ITEM.defaultValue) 129 } 130 131 @Test get_stringItemNotInLauncherPrefs_returnsDefaultValuenull132 fun get_stringItemNotInLauncherPrefs_returnsDefaultValue() { 133 assertThat(launcherPrefs.get(TEST_STRING_ITEM)).isEqualTo(TEST_STRING_ITEM.defaultValue) 134 } 135 136 @Test get_intItemNotInLauncherprefs_returnsDefaultValuenull137 fun get_intItemNotInLauncherprefs_returnsDefaultValue() { 138 assertThat(launcherPrefs.get(TEST_INT_ITEM)).isEqualTo(TEST_INT_ITEM.defaultValue) 139 } 140 141 @Test put_storesItemInLauncherPrefs_successfullynull142 fun put_storesItemInLauncherPrefs_successfully() { 143 val notDefaultValue = !TEST_BOOLEAN_ITEM.defaultValue 144 145 with(launcherPrefs) { 146 putSync(TEST_BOOLEAN_ITEM.to(notDefaultValue)) 147 assertThat(get(TEST_BOOLEAN_ITEM)).isEqualTo(notDefaultValue) 148 remove(TEST_BOOLEAN_ITEM) 149 } 150 } 151 152 @Test whenItemType_isInvalid_thenThrowExceptionnull153 fun whenItemType_isInvalid_thenThrowException() { 154 val badItem = LauncherPrefs.nonRestorableItem("8", mapOf<String, String>()) 155 with(launcherPrefs) { 156 assertThrows(IllegalArgumentException::class.java) { 157 putSync(badItem.to(badItem.defaultValue)) 158 } 159 assertThrows(IllegalArgumentException::class.java) { get(badItem) } 160 } 161 } 162 163 @Test put_storesListOfItemsInLauncherPrefs_successfullynull164 fun put_storesListOfItemsInLauncherPrefs_successfully() { 165 with(launcherPrefs) { 166 putSync( 167 TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue), 168 TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue), 169 TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue), 170 TEST_FLOAT_ITEM.to(TEST_FLOAT_ITEM.defaultValue), 171 TEST_LONG_ITEM.to(TEST_LONG_ITEM.defaultValue), 172 TEST_SET_ITEM.to(TEST_SET_ITEM.defaultValue), 173 TEST_HASHSET_ITEM.to(TEST_HASHSET_ITEM.defaultValue), 174 ) 175 assertThat( 176 has( 177 TEST_STRING_ITEM, 178 TEST_INT_ITEM, 179 TEST_BOOLEAN_ITEM, 180 TEST_FLOAT_ITEM, 181 TEST_LONG_ITEM, 182 TEST_SET_ITEM, 183 TEST_HASHSET_ITEM, 184 ) 185 ) 186 .isTrue() 187 remove( 188 TEST_STRING_ITEM, 189 TEST_INT_ITEM, 190 TEST_BOOLEAN_ITEM, 191 TEST_FLOAT_ITEM, 192 TEST_LONG_ITEM, 193 TEST_SET_ITEM, 194 TEST_HASHSET_ITEM, 195 ) 196 } 197 } 198 199 @Test remove_deletesItemFromLauncherPrefs_successfullynull200 fun remove_deletesItemFromLauncherPrefs_successfully() { 201 val notDefaultValue = !TEST_BOOLEAN_ITEM.defaultValue 202 203 with(launcherPrefs) { 204 putSync(TEST_BOOLEAN_ITEM.to(notDefaultValue)) 205 remove(TEST_BOOLEAN_ITEM) 206 assertThat(get(TEST_BOOLEAN_ITEM)).isEqualTo(TEST_BOOLEAN_ITEM.defaultValue) 207 } 208 } 209 210 @Test get_contextualItem_returnsCorrectDefaultnull211 fun get_contextualItem_returnsCorrectDefault() { 212 assertThat(launcherPrefs.get(TEST_CONTEXTUAL_ITEM)).isTrue() 213 } 214 215 @Test getItemSharedPrefFile_forNonRestorableItem_isCorrectnull216 fun getItemSharedPrefFile_forNonRestorableItem_isCorrect() { 217 val nonRestorableItem = LauncherPrefs.nonRestorableItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE) 218 assertThat(nonRestorableItem.sharedPrefFile).isEqualTo(LauncherFiles.DEVICE_PREFERENCES_KEY) 219 } 220 221 @Test getItemSharedPrefFile_forBackedUpItem_isCorrectnull222 fun getItemSharedPrefFile_forBackedUpItem_isCorrect() { 223 val backedUpItem = LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE) 224 assertThat(backedUpItem.sharedPrefFile).isEqualTo(LauncherFiles.SHARED_PREFERENCES_KEY) 225 } 226 227 @Test put_bootAwareItem_updatesDeviceProtectedStoragenull228 fun put_bootAwareItem_updatesDeviceProtectedStorage() { 229 val bootAwareItem = 230 LauncherPrefs.backedUpItem( 231 TEST_PREF_KEY, 232 TEST_DEFAULT_VALUE, 233 EncryptionType.DEVICE_PROTECTED, 234 ) 235 236 val bootAwarePrefs: SharedPreferences = 237 context 238 .createDeviceProtectedStorageContext() 239 .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE) 240 bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit() 241 242 launcherPrefs.putSync(bootAwareItem.to(bootAwareItem.defaultValue)) 243 assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue() 244 245 launcherPrefs.removeSync(bootAwareItem) 246 } 247 248 @Test remove_bootAwareItem_removesFromDeviceProtectedStoragenull249 fun remove_bootAwareItem_removesFromDeviceProtectedStorage() { 250 val bootAwareItem = 251 LauncherPrefs.backedUpItem( 252 TEST_PREF_KEY, 253 TEST_DEFAULT_VALUE, 254 EncryptionType.DEVICE_PROTECTED, 255 ) 256 257 val bootAwarePrefs: SharedPreferences = 258 context 259 .createDeviceProtectedStorageContext() 260 .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE) 261 262 bootAwarePrefs 263 .edit() 264 .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue) 265 .commit() 266 267 launcherPrefs.removeSync(bootAwareItem) 268 assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isFalse() 269 } 270 } 271