1 /* <lambda>null2 * 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 android.content.SharedPreferences.OnSharedPreferenceChangeListener 21 import androidx.test.ext.junit.runners.AndroidJUnit4 22 import androidx.test.filters.SmallTest 23 import androidx.test.platform.app.InstrumentationRegistry 24 import com.android.launcher3.LauncherPrefs.Companion.BOOT_AWARE_PREFS_KEY 25 import com.google.common.truth.Truth.assertThat 26 import java.util.concurrent.CountDownLatch 27 import java.util.concurrent.TimeUnit 28 import org.junit.AfterClass 29 import org.junit.BeforeClass 30 import org.junit.Test 31 import org.junit.runner.RunWith 32 33 private val TEST_BOOLEAN_ITEM = LauncherPrefs.nonRestorableItem("1", false) 34 private val TEST_STRING_ITEM = LauncherPrefs.nonRestorableItem("2", "( ͡❛ ͜ʖ ͡❛)") 35 private val TEST_INT_ITEM = LauncherPrefs.nonRestorableItem("3", -1) 36 private val TEST_CONTEXTUAL_ITEM = ContextualItem("4", true, { true }, false, Boolean::class.java) 37 38 private const val TEST_DEFAULT_VALUE = "default" 39 private const val TEST_PREF_KEY = "test_pref_key" 40 41 private const val WAIT_TIME_IN_SECONDS = 3L 42 43 @SmallTest 44 @RunWith(AndroidJUnit4::class) 45 class LauncherPrefsTest { 46 <lambda>null47 private val context by lazy { InstrumentationRegistry.getInstrumentation().targetContext } <lambda>null48 private val launcherPrefs by lazy { LauncherPrefs.get(context) } 49 50 companion object { 51 @BeforeClass 52 @JvmStatic setupnull53 fun setup() { 54 isBootAwareStartupDataEnabled = true 55 } 56 57 @AfterClass 58 @JvmStatic teardownnull59 fun teardown() { 60 isBootAwareStartupDataEnabled = false 61 } 62 } 63 64 @Test has_keyMissingFromLauncherPrefs_returnsFalsenull65 fun has_keyMissingFromLauncherPrefs_returnsFalse() { 66 assertThat(launcherPrefs.has(TEST_BOOLEAN_ITEM)).isFalse() 67 } 68 69 @Test has_keyPresentInLauncherPrefs_returnsTruenull70 fun has_keyPresentInLauncherPrefs_returnsTrue() { 71 with(launcherPrefs) { 72 putSync(TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue)) 73 assertThat(has(TEST_BOOLEAN_ITEM)).isTrue() 74 remove(TEST_BOOLEAN_ITEM) 75 } 76 } 77 78 @Test addListener_listeningForStringItemUpdates_isCorrectlyNotifiedOfUpdatesnull79 fun addListener_listeningForStringItemUpdates_isCorrectlyNotifiedOfUpdates() { 80 val latch = CountDownLatch(1) 81 val listener = OnSharedPreferenceChangeListener { _, _ -> latch.countDown() } 82 83 with(launcherPrefs) { 84 putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue)) 85 addListener(listener, TEST_STRING_ITEM) 86 putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "abc")) 87 88 assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isTrue() 89 remove(TEST_STRING_ITEM) 90 } 91 } 92 93 @Test removeListener_previouslyListeningForStringItemUpdates_isNoLongerNotifiedOfUpdatesnull94 fun removeListener_previouslyListeningForStringItemUpdates_isNoLongerNotifiedOfUpdates() { 95 val latch = CountDownLatch(1) 96 val listener = OnSharedPreferenceChangeListener { _, _ -> latch.countDown() } 97 98 with(launcherPrefs) { 99 addListener(listener, TEST_STRING_ITEM) 100 removeListener(listener, TEST_STRING_ITEM) 101 putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "hello.")) 102 103 // latch will be still be 1 (and await will return false) if the listener was not called 104 assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isFalse() 105 remove(TEST_STRING_ITEM) 106 } 107 } 108 109 @Test addListenerAndRemoveListener_forMultipleItems_bothWorkProperlynull110 fun addListenerAndRemoveListener_forMultipleItems_bothWorkProperly() { 111 var latch = CountDownLatch(3) 112 val listener = OnSharedPreferenceChangeListener { _, _ -> latch.countDown() } 113 114 with(launcherPrefs) { 115 addListener(listener, TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM) 116 putSync( 117 TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue + 123), 118 TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "abc"), 119 TEST_BOOLEAN_ITEM.to(!TEST_BOOLEAN_ITEM.defaultValue) 120 ) 121 assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isTrue() 122 123 removeListener(listener, TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM) 124 latch = CountDownLatch(1) 125 putSync( 126 TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue), 127 TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue), 128 TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue) 129 ) 130 remove(TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM) 131 132 assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isFalse() 133 } 134 } 135 136 @Test get_booleanItemNotInLauncherprefs_returnsDefaultValuenull137 fun get_booleanItemNotInLauncherprefs_returnsDefaultValue() { 138 assertThat(launcherPrefs.get(TEST_BOOLEAN_ITEM)).isEqualTo(TEST_BOOLEAN_ITEM.defaultValue) 139 } 140 141 @Test get_stringItemNotInLauncherPrefs_returnsDefaultValuenull142 fun get_stringItemNotInLauncherPrefs_returnsDefaultValue() { 143 assertThat(launcherPrefs.get(TEST_STRING_ITEM)).isEqualTo(TEST_STRING_ITEM.defaultValue) 144 } 145 146 @Test get_intItemNotInLauncherprefs_returnsDefaultValuenull147 fun get_intItemNotInLauncherprefs_returnsDefaultValue() { 148 assertThat(launcherPrefs.get(TEST_INT_ITEM)).isEqualTo(TEST_INT_ITEM.defaultValue) 149 } 150 151 @Test put_storesItemInLauncherPrefs_successfullynull152 fun put_storesItemInLauncherPrefs_successfully() { 153 val notDefaultValue = !TEST_BOOLEAN_ITEM.defaultValue 154 155 with(launcherPrefs) { 156 putSync(TEST_BOOLEAN_ITEM.to(notDefaultValue)) 157 assertThat(get(TEST_BOOLEAN_ITEM)).isEqualTo(notDefaultValue) 158 remove(TEST_BOOLEAN_ITEM) 159 } 160 } 161 162 @Test put_storesListOfItemsInLauncherPrefs_successfullynull163 fun put_storesListOfItemsInLauncherPrefs_successfully() { 164 with(launcherPrefs) { 165 putSync( 166 TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue), 167 TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue), 168 TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue) 169 ) 170 assertThat(has(TEST_BOOLEAN_ITEM, TEST_INT_ITEM, TEST_STRING_ITEM)).isTrue() 171 remove(TEST_STRING_ITEM, TEST_INT_ITEM, TEST_BOOLEAN_ITEM) 172 } 173 } 174 175 @Test remove_deletesItemFromLauncherPrefs_successfullynull176 fun remove_deletesItemFromLauncherPrefs_successfully() { 177 val notDefaultValue = !TEST_BOOLEAN_ITEM.defaultValue 178 179 with(launcherPrefs) { 180 putSync(TEST_BOOLEAN_ITEM.to(notDefaultValue)) 181 remove(TEST_BOOLEAN_ITEM) 182 assertThat(get(TEST_BOOLEAN_ITEM)).isEqualTo(TEST_BOOLEAN_ITEM.defaultValue) 183 } 184 } 185 186 @Test get_contextualItem_returnsCorrectDefaultnull187 fun get_contextualItem_returnsCorrectDefault() { 188 assertThat(launcherPrefs.get(TEST_CONTEXTUAL_ITEM)).isTrue() 189 } 190 191 @Test getItemSharedPrefFile_forNonRestorableItem_isCorrectnull192 fun getItemSharedPrefFile_forNonRestorableItem_isCorrect() { 193 val nonRestorableItem = LauncherPrefs.nonRestorableItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE) 194 assertThat(nonRestorableItem.sharedPrefFile).isEqualTo(LauncherFiles.DEVICE_PREFERENCES_KEY) 195 } 196 197 @Test getItemSharedPrefFile_forBackedUpItem_isCorrectnull198 fun getItemSharedPrefFile_forBackedUpItem_isCorrect() { 199 val backedUpItem = LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE) 200 assertThat(backedUpItem.sharedPrefFile).isEqualTo(LauncherFiles.SHARED_PREFERENCES_KEY) 201 } 202 203 @Test put_bootAwareItem_updatesDeviceProtectedStoragenull204 fun put_bootAwareItem_updatesDeviceProtectedStorage() { 205 val bootAwareItem = 206 LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true) 207 208 val bootAwarePrefs: SharedPreferences = 209 context 210 .createDeviceProtectedStorageContext() 211 .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE) 212 bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit() 213 214 launcherPrefs.putSync(bootAwareItem.to(bootAwareItem.defaultValue)) 215 assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue() 216 217 launcherPrefs.removeSync(bootAwareItem) 218 } 219 220 @Test put_bootAwareItem_updatesEncryptedStoragenull221 fun put_bootAwareItem_updatesEncryptedStorage() { 222 val bootAwareItem = 223 LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true) 224 225 val encryptedPrefs: SharedPreferences = 226 context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE) 227 encryptedPrefs.edit().remove(bootAwareItem.sharedPrefKey).commit() 228 229 launcherPrefs.putSync(bootAwareItem.to(TEST_STRING_ITEM.defaultValue)) 230 assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isTrue() 231 232 launcherPrefs.removeSync(bootAwareItem) 233 } 234 235 @Test remove_bootAwareItem_removesFromDeviceProtectedStoragenull236 fun remove_bootAwareItem_removesFromDeviceProtectedStorage() { 237 val bootAwareItem = 238 LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true) 239 240 val bootAwarePrefs: SharedPreferences = 241 context 242 .createDeviceProtectedStorageContext() 243 .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE) 244 245 bootAwarePrefs 246 .edit() 247 .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue) 248 .commit() 249 250 launcherPrefs.removeSync(bootAwareItem) 251 assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isFalse() 252 } 253 254 @Test remove_bootAwareItem_removesFromEncryptedStoragenull255 fun remove_bootAwareItem_removesFromEncryptedStorage() { 256 val bootAwareItem = 257 LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true) 258 259 val encryptedPrefs: SharedPreferences = 260 context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE) 261 262 encryptedPrefs 263 .edit() 264 .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue) 265 .commit() 266 267 launcherPrefs.removeSync(bootAwareItem) 268 assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isFalse() 269 } 270 271 @Test migrate_bootAwareItemsToDeviceProtectedStorage_worksAsIntendednull272 fun migrate_bootAwareItemsToDeviceProtectedStorage_worksAsIntended() { 273 val bootAwareItem = 274 LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true) 275 launcherPrefs.removeSync(bootAwareItem) 276 277 val bootAwarePrefs: SharedPreferences = 278 context 279 .createDeviceProtectedStorageContext() 280 .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE) 281 282 if (bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)) { 283 bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit() 284 } 285 286 val encryptedPrefs: SharedPreferences = 287 context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE) 288 289 encryptedPrefs 290 .edit() 291 .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue) 292 .commit() 293 294 launcherPrefs.migrateStartupDataToDeviceProtectedStorage() 295 assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue() 296 297 launcherPrefs.removeSync(bootAwareItem) 298 } 299 300 @Test migrate_onlyEncryptedItemsToDeviceProtectedStorage_doesNotHappennull301 fun migrate_onlyEncryptedItemsToDeviceProtectedStorage_doesNotHappen() { 302 val onlyEncryptedItem = 303 LauncherPrefs.backedUpItem( 304 TEST_PREF_KEY + "_", 305 TEST_DEFAULT_VALUE + "_", 306 isBootAware = false 307 ) 308 309 val bootAwarePrefs: SharedPreferences = 310 context 311 .createDeviceProtectedStorageContext() 312 .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE) 313 314 if (bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)) { 315 bootAwarePrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit() 316 } 317 318 val encryptedPrefs: SharedPreferences = 319 context.getSharedPreferences(onlyEncryptedItem.sharedPrefFile, Context.MODE_PRIVATE) 320 321 encryptedPrefs 322 .edit() 323 .putString(onlyEncryptedItem.sharedPrefKey, onlyEncryptedItem.defaultValue) 324 .commit() 325 326 launcherPrefs.migrateStartupDataToDeviceProtectedStorage() 327 assertThat(bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)).isFalse() 328 329 encryptedPrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit() 330 } 331 } 332