Revert "Remove Unused parts of LauncherPrefs causing cyclical dependency."
This reverts commit 21ab3b979b78d15d71f979f6290844b0dd1795ee.
Reason for revert: Culprit for b/326611479. Will be verifying through ABTD for confirmation and before submitting the revert.
Change-Id: Ib71791d159b3ac65ca332f58500341a1a0fe36e1
diff --git a/quickstep/src/com/android/quickstep/BootAwarePreloader.kt b/quickstep/src/com/android/quickstep/BootAwarePreloader.kt
new file mode 100644
index 0000000..2fc4d04
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/BootAwarePreloader.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.quickstep
+
+import android.content.Context
+import android.util.Log
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.moveStartupDataToDeviceProtectedStorageIsEnabled
+import com.android.launcher3.util.LockedUserState
+
+/**
+ * Loads expensive objects in memory before the user is unlocked. This decreases experienced latency
+ * when starting the launcher for the first time after a reboot.
+ */
+object BootAwarePreloader {
+ private const val TAG = "BootAwarePreloader"
+
+ @JvmStatic
+ fun start(context: Context) {
+ val lp = LauncherPrefs.get(context)
+ when {
+ LockedUserState.get(context).isUserUnlocked ||
+ !moveStartupDataToDeviceProtectedStorageIsEnabled -> {
+ /* No-Op */
+ }
+ lp.isStartupDataMigrated -> {
+ Log.d(TAG, "preloading start up data")
+ LauncherAppState.INSTANCE.get(context)
+ }
+ else -> {
+ Log.d(TAG, "queuing start up data migration to boot aware prefs")
+ LockedUserState.get(context).runOnUserUnlocked {
+ lp.migrateStartupDataToDeviceProtectedStorage()
+ }
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 8619b4d..f9486bd 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -493,6 +493,7 @@
mTaskbarManager = new TaskbarManager(this);
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
+ BootAwarePreloader.start(this);
// Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
LockedUserState.get(this).runOnUserUnlocked(this::onUserUnlocked);
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index d7e6387..b0a644b 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -19,6 +19,7 @@
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
+import android.util.Log
import android.view.ViewConfiguration
import androidx.annotation.VisibleForTesting
import com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN
@@ -37,6 +38,8 @@
* Use same context for shared preferences, so that we use a single cached instance
*
* TODO(b/262721340): Replace all direct SharedPreference refs with LauncherPrefs / Item methods.
+ * TODO(b/274501660): Fix ReorderWidgets#simpleReorder test before enabling
+ * isBootAwareStartupDataEnabled
*/
class LauncherPrefs(private val encryptedContext: Context) {
private val deviceProtectedStorageContext =
@@ -49,8 +52,22 @@
private val Item.encryptedPrefs
get() = encryptedContext.getSharedPreferences(sharedPrefFile, MODE_PRIVATE)
+ // This call to `SharedPreferences` needs to be explicit rather than using `get` since doing so
+ // would result in a circular dependency between `isStartupDataMigrated` and `choosePreferences`
+ val isStartupDataMigrated: Boolean
+ get() =
+ bootAwarePrefs.getBoolean(
+ IS_STARTUP_DATA_MIGRATED.sharedPrefKey,
+ IS_STARTUP_DATA_MIGRATED.defaultValue
+ )
+
private fun chooseSharedPreferences(item: Item): SharedPreferences =
- if (item.encryptionType == EncryptionType.DEVICE_PROTECTED) bootAwarePrefs
+ if (
+ (moveStartupDataToDeviceProtectedStorageIsEnabled &&
+ item.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
+ isStartupDataMigrated) || item.encryptionType == EncryptionType.DEVICE_PROTECTED
+ )
+ bootAwarePrefs
else item.encryptedPrefs
/** Wrapper around `getInner` for a `ContextualItem` */
@@ -130,7 +147,11 @@
.toMutableMap()
val bootAwareUpdates =
- updates.filter { it.first.encryptionType == EncryptionType.DEVICE_PROTECTED }
+ updates.filter {
+ (it.first.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
+ moveStartupDataToDeviceProtectedStorageIsEnabled) ||
+ it.first.encryptionType == EncryptionType.DEVICE_PROTECTED
+ }
if (bootAwareUpdates.isNotEmpty()) {
updatesPerPrefFile[bootAwarePrefs] = bootAwareUpdates
}
@@ -231,7 +252,12 @@
.groupBy { it.encryptedPrefs }
.toMutableMap()
- val bootAwareUpdates = items.filter { it.encryptionType == EncryptionType.DEVICE_PROTECTED }
+ val bootAwareUpdates =
+ items.filter {
+ (it.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
+ moveStartupDataToDeviceProtectedStorageIsEnabled) ||
+ it.encryptionType == EncryptionType.DEVICE_PROTECTED
+ }
if (bootAwareUpdates.isNotEmpty()) {
itemsPerFile[bootAwarePrefs] = bootAwareUpdates
}
@@ -243,7 +269,24 @@
}
}
+ fun migrateStartupDataToDeviceProtectedStorage() {
+ if (!moveStartupDataToDeviceProtectedStorageIsEnabled) return
+
+ Log.d(
+ TAG,
+ "Migrating data to unencrypted shared preferences to enable preloading " +
+ "while the user is locked the next time the device reboots."
+ )
+
+ with(bootAwarePrefs.edit()) {
+ ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE.forEach { putValue(it, get(it)) }
+ putBoolean(IS_STARTUP_DATA_MIGRATED.sharedPrefKey, true)
+ apply()
+ }
+ }
+
companion object {
+ private const val TAG = "LauncherPrefs"
@VisibleForTesting const val BOOT_AWARE_PREFS_KEY = "boot_aware_prefs"
@JvmField var INSTANCE = MainThreadInitializedObject { LauncherPrefs(it) }
@@ -253,50 +296,80 @@
const val TASKBAR_PINNING_KEY = "TASKBAR_PINNING_KEY"
const val SHOULD_SHOW_SMARTSPACE_KEY = "SHOULD_SHOW_SMARTSPACE_KEY"
@JvmField
- val ICON_STATE = nonRestorableItem("pref_icon_shape_path", "", EncryptionType.ENCRYPTED)
+ val ICON_STATE =
+ nonRestorableItem("pref_icon_shape_path", "", EncryptionType.MOVE_TO_DEVICE_PROTECTED)
@JvmField
val ALL_APPS_OVERVIEW_THRESHOLD =
- nonRestorableItem("pref_all_apps_overview_threshold", 180, EncryptionType.ENCRYPTED)
+ nonRestorableItem(
+ "pref_all_apps_overview_threshold",
+ 180,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE =
- nonRestorableItem("LPNH_SLOP_PERCENTAGE", 100, EncryptionType.ENCRYPTED)
+ nonRestorableItem("LPNH_SLOP_PERCENTAGE", 100, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
@JvmField
val LONG_PRESS_NAV_HANDLE_TIMEOUT_MS =
nonRestorableItem(
"LPNH_TIMEOUT_MS",
ViewConfiguration.getLongPressTimeout(),
- EncryptionType.ENCRYPTED
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_START_SCALE_PERCENT =
- nonRestorableItem("LPNH_HAPTIC_HINT_START_SCALE_PERCENT", 0, EncryptionType.ENCRYPTED)
+ nonRestorableItem(
+ "LPNH_HAPTIC_HINT_START_SCALE_PERCENT",
+ 0,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT =
- nonRestorableItem("LPNH_HAPTIC_HINT_END_SCALE_PERCENT", 100, EncryptionType.ENCRYPTED)
+ nonRestorableItem(
+ "LPNH_HAPTIC_HINT_END_SCALE_PERCENT",
+ 100,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT =
- nonRestorableItem("LPNH_HAPTIC_HINT_SCALE_EXPONENT", 1, EncryptionType.ENCRYPTED)
+ nonRestorableItem(
+ "LPNH_HAPTIC_HINT_SCALE_EXPONENT",
+ 1,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS =
- nonRestorableItem("LPNH_HAPTIC_HINT_ITERATIONS", 50, EncryptionType.ENCRYPTED)
+ nonRestorableItem(
+ "LPNH_HAPTIC_HINT_ITERATIONS",
+ 50,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY =
- nonRestorableItem("LPNH_HAPTIC_HINT_DELAY", 0, EncryptionType.ENCRYPTED)
+ nonRestorableItem("LPNH_HAPTIC_HINT_DELAY", 0, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
@JvmField
val PRIVATE_SPACE_APPS =
- nonRestorableItem("pref_private_space_apps", 0, EncryptionType.ENCRYPTED)
+ nonRestorableItem("pref_private_space_apps", 0, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
+ @JvmField val ENABLE_TWOLINE_ALLAPPS_TOGGLE =
+ backedUpItem("pref_enable_two_line_toggle", false)
@JvmField
- val ENABLE_TWOLINE_ALLAPPS_TOGGLE = backedUpItem("pref_enable_two_line_toggle", false)
- @JvmField
- val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.ENCRYPTED)
+ val THEMED_ICONS =
+ backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
@JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
@JvmField val WORK_EDU_STEP = backedUpItem("showed_work_profile_edu", 0)
@JvmField
val WORKSPACE_SIZE =
- backedUpItem(DeviceGridState.KEY_WORKSPACE_SIZE, "", EncryptionType.ENCRYPTED)
+ backedUpItem(
+ DeviceGridState.KEY_WORKSPACE_SIZE,
+ "",
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val HOTSEAT_COUNT =
- backedUpItem(DeviceGridState.KEY_HOTSEAT_COUNT, -1, EncryptionType.ENCRYPTED)
+ backedUpItem(
+ DeviceGridState.KEY_HOTSEAT_COUNT,
+ -1,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val TASKBAR_PINNING =
backedUpItem(TASKBAR_PINNING_KEY, false, EncryptionType.DEVICE_PROTECTED)
@@ -306,10 +379,11 @@
backedUpItem(
DeviceGridState.KEY_DEVICE_TYPE,
InvariantDeviceProfile.TYPE_PHONE,
- EncryptionType.ENCRYPTED
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
@JvmField
- val DB_FILE = backedUpItem(DeviceGridState.KEY_DB_FILE, "", EncryptionType.ENCRYPTED)
+ val DB_FILE =
+ backedUpItem(DeviceGridState.KEY_DB_FILE, "", EncryptionType.MOVE_TO_DEVICE_PROTECTED)
@JvmField
val SHOULD_SHOW_SMARTSPACE =
backedUpItem(
@@ -322,11 +396,15 @@
backedUpItem(
RestoreDbTask.RESTORED_DEVICE_TYPE,
InvariantDeviceProfile.TYPE_PHONE,
- EncryptionType.ENCRYPTED
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
@JvmField
val IS_FIRST_LOAD_AFTER_RESTORE =
- nonRestorableItem(FIRST_LOAD_AFTER_RESTORE_KEY, false, EncryptionType.ENCRYPTED)
+ nonRestorableItem(
+ FIRST_LOAD_AFTER_RESTORE_KEY,
+ false,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "")
@JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "")
@JvmField
@@ -335,7 +413,7 @@
"idp_grid_name",
isBackedUp = true,
defaultValue = null,
- encryptionType = EncryptionType.ENCRYPTED,
+ encryptionType = EncryptionType.MOVE_TO_DEVICE_PROTECTED,
type = String::class.java
)
@JvmField
@@ -343,6 +421,14 @@
backedUpItem(RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY, Boolean::class.java) {
RotationHelper.getAllowRotationDefaultValue(DisplayController.INSTANCE.get(it).info)
}
+ @JvmField
+ val IS_STARTUP_DATA_MIGRATED =
+ ConstantItem(
+ "is_startup_data_boot_aware",
+ isBackedUp = false,
+ defaultValue = false,
+ encryptionType = EncryptionType.DEVICE_PROTECTED
+ )
// Preferences for widget configurations
@JvmField
@@ -407,6 +493,12 @@
}
}
+// It is a var because the unit tests are setting this to true so they can run.
+var moveStartupDataToDeviceProtectedStorageIsEnabled: Boolean =
+ com.android.launcher3.config.FeatureFlags.MOVE_STARTUP_DATA_TO_DEVICE_PROTECTED_STORAGE.get()
+
+private val ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE: MutableSet<ConstantItem<*>> = mutableSetOf()
+
abstract class Item {
abstract val sharedPrefKey: String
abstract val isBackedUp: Boolean
@@ -426,6 +518,14 @@
// The default value can be null. If so, the type needs to be explicitly stated, or else NPE
override val type: Class<out T> = defaultValue!!::class.java
) : Item() {
+ init {
+ if (
+ encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
+ moveStartupDataToDeviceProtectedStorageIsEnabled
+ ) {
+ ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE.add(this)
+ }
+ }
fun get(c: Context): T = LauncherPrefs.get(c).get(this)
}
@@ -452,4 +552,5 @@
enum class EncryptionType {
ENCRYPTED,
DEVICE_PROTECTED,
+ MOVE_TO_DEVICE_PROTECTED
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 8c0dc89..072a96c 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -100,6 +100,13 @@
public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476,
"ENABLE_DISMISS_PREDICTION_UNDO", DISABLED,
"Show an 'Undo' snackbar when users dismiss a predicted hotseat item");
+
+ public static final BooleanFlag MOVE_STARTUP_DATA_TO_DEVICE_PROTECTED_STORAGE = getDebugFlag(
+ 251502424, "ENABLE_BOOT_AWARE_STARTUP_DATA", DISABLED,
+ "Marks LauncherPref data as (and allows it to) available while the device is"
+ + " locked. Enabling this causes a 1-time movement of certain SharedPreferences"
+ + " data. Improves startup latency.");
+
public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171,
"CONTINUOUS_VIEW_TREE_CAPTURE", ENABLED, "Capture View tree every frame");
diff --git a/tests/src/com/android/launcher3/LauncherPrefsTest.kt b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
index b813095..88a430b 100644
--- a/tests/src/com/android/launcher3/LauncherPrefsTest.kt
+++ b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
@@ -25,6 +25,8 @@
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
@@ -46,6 +48,20 @@
private val context by lazy { InstrumentationRegistry.getInstrumentation().targetContext }
private val launcherPrefs by lazy { LauncherPrefs.get(context) }
+ companion object {
+ @BeforeClass
+ @JvmStatic
+ fun setup() {
+ moveStartupDataToDeviceProtectedStorageIsEnabled = true
+ }
+
+ @AfterClass
+ @JvmStatic
+ fun teardown() {
+ moveStartupDataToDeviceProtectedStorageIsEnabled = false
+ }
+ }
+
@Test
fun has_keyMissingFromLauncherPrefs_returnsFalse() {
assertThat(launcherPrefs.has(TEST_BOOLEAN_ITEM)).isFalse()
@@ -207,12 +223,31 @@
}
@Test
+ fun put_bootAwareItem_updatesEncryptedStorage() {
+ val bootAwareItem =
+ LauncherPrefs.backedUpItem(
+ TEST_PREF_KEY,
+ TEST_DEFAULT_VALUE,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
+
+ 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,
- EncryptionType.DEVICE_PROTECTED
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
val bootAwarePrefs: SharedPreferences =
@@ -228,4 +263,90 @@
launcherPrefs.removeSync(bootAwareItem)
assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
}
+
+ @Test
+ fun remove_bootAwareItem_removesFromEncryptedStorage() {
+ val bootAwareItem =
+ LauncherPrefs.backedUpItem(
+ TEST_PREF_KEY,
+ TEST_DEFAULT_VALUE,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
+
+ 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,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
+ 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 + "_",
+ EncryptionType.ENCRYPTED
+ )
+
+ 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()
+ }
}