• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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