Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ef7e1db authored by Bharat Singh's avatar Bharat Singh Committed by Android (Google) Code Review
Browse files

Merge "[SysUI][Floaty] Fix logic for saving invocation effect preferences" into main

parents b5d34ad7 111f02ac
Loading
Loading
Loading
Loading
+101 −15
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.shared.Flags
import com.android.systemui.testKosmos
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.DEFAULT_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.DEFAULT_INWARD_EFFECT_PADDING_DURATION_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.DEFAULT_OUTWARD_EFFECT_DURATION_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS
import com.android.systemui.topwindoweffects.data.repository.SqueezeEffectRepositoryImpl.Companion.IS_INVOCATION_EFFECT_ENABLED_KEY
@@ -162,7 +165,14 @@ class SqueezeEffectRepositoryTest : SysuiTestCase() {
    @Test
    fun testInvocationEffectInwardsAnimationDelay() =
        kosmos.runTest {
            fakeInvocationEffectPreferences.setInwardAnimationPaddingDurationMillis(450)
            fakeInvocationEffectPreferences.setInvocationEffectConfig(
                InvocationEffectPreferences.Config(
                    isEnabled = true,
                    inwardsEffectDurationPadding = 450,
                    outwardsEffectDuration = 400,
                ),
                true,
            )

            assertThat(underTest.getInvocationEffectInAnimationDurationMillis()).isEqualTo(800)
        }
@@ -171,44 +181,120 @@ class SqueezeEffectRepositoryTest : SysuiTestCase() {
    @Test
    fun testInvocationEffectOutwardsAnimationDelay() =
        kosmos.runTest {
            fakeInvocationEffectPreferences.setOutwardAnimationDurationMillis(400)
            fakeInvocationEffectPreferences.setInvocationEffectConfig(
                InvocationEffectPreferences.Config(
                    isEnabled = true,
                    inwardsEffectDurationPadding = 450,
                    outwardsEffectDuration = 400,
                ),
                true,
            )

            assertThat(underTest.getInvocationEffectOutAnimationDurationMillis()).isEqualTo(400)
        }

    @EnableFlags(Flags.FLAG_ENABLE_LPP_ASSIST_INVOCATION_EFFECT)
    @Test
    fun testSetUiHintsShouldUpdatePreferences() =
    fun testSetUiHints_whenSuppliedAllConfigs_allUpdatedInPreferences() =
        kosmos.runTest {
            fakeInvocationEffectPreferences.activeUserId = 1
            fakeInvocationEffectPreferences.activeAssistant = "A"

            assertThat(fakeInvocationEffectPreferences.isActiveUserAndAssistantPersisted())
            assertThat(fakeInvocationEffectPreferences.isCurrentUserAndAssistantPersisted())
                .isFalse()

            val hints = createAssistantSettingBundle(false, 0, 1000)
            val hints =
                createAssistantSettingBundle(
                    enableAssistantSetting = false,
                    inwardsPaddingDuration = 0,
                    outwardsAnimationDuration = 1000,
                )
            underTest.tryHandleSetUiHints(hints)

            val isEffectEnabledAndPowerButtonPressed by
                collectLastValue(underTest.isEffectEnabledAndPowerButtonPressedAsSingleGesture)
            assertThat(fakeInvocationEffectPreferences.getInwardAnimationPaddingDurationMillis())
                .isEqualTo(0)
            assertThat(fakeInvocationEffectPreferences.getOutwardAnimationDurationMillis())
                .isEqualTo(1000)
            assertThat(fakeInvocationEffectPreferences.isInvocationEffectEnabledInPreferences())
                .isFalse()
            assertThat(fakeInvocationEffectPreferences.isCurrentUserAndAssistantPersisted())
                .isTrue()
        }

    @EnableFlags(Flags.FLAG_ENABLE_LPP_ASSIST_INVOCATION_EFFECT)
    @Test
    fun testSetUiHints_whenSuppliedPartialConfig() =
        kosmos.runTest {
            fakeInvocationEffectPreferences.activeUserId = 1
            fakeInvocationEffectPreferences.activeAssistant = "A"

            assertThat(fakeInvocationEffectPreferences.isCurrentUserAndAssistantPersisted())
                .isFalse()

            underTest.tryHandleSetUiHints(
                createAssistantSettingBundle(
                    enableAssistantSetting = false,
                    inwardsPaddingDuration = 0,
                    outwardsAnimationDuration = 1000,
                )
            )

            assertThat(isEffectEnabledAndPowerButtonPressed).isFalse()
            assertThat(fakeInvocationEffectPreferences.getInwardAnimationPaddingDurationMillis())
                .isEqualTo(0)
            assertThat(fakeInvocationEffectPreferences.getOutwardAnimationDurationMillis())
                .isEqualTo(1000)
            assertThat(fakeInvocationEffectPreferences.isActiveUserAndAssistantPersisted()).isTrue()
            assertThat(fakeInvocationEffectPreferences.isInvocationEffectEnabledInPreferences())
                .isFalse()
            assertThat(fakeInvocationEffectPreferences.isCurrentUserAndAssistantPersisted())
                .isTrue()

            underTest.tryHandleSetUiHints(
                createAssistantSettingBundle(enableAssistantSetting = true)
            )

            assertThat(fakeInvocationEffectPreferences.getInwardAnimationPaddingDurationMillis())
                .isEqualTo(0)
            assertThat(fakeInvocationEffectPreferences.getOutwardAnimationDurationMillis())
                .isEqualTo(1000)
            assertThat(fakeInvocationEffectPreferences.isInvocationEffectEnabledInPreferences())
                .isTrue()
        }

    @EnableFlags(Flags.FLAG_ENABLE_LPP_ASSIST_INVOCATION_EFFECT)
    @Test
    fun testSetUiHints_whenSuppliedNoConfig_shouldSetDefaults() =
        kosmos.runTest {
            fakeInvocationEffectPreferences.activeUserId = 1
            fakeInvocationEffectPreferences.activeAssistant = "A"

            assertThat(fakeInvocationEffectPreferences.isCurrentUserAndAssistantPersisted())
                .isFalse()

            underTest.tryHandleSetUiHints(createAssistantSettingBundle())

            assertThat(fakeInvocationEffectPreferences.getInwardAnimationPaddingDurationMillis())
                .isEqualTo(DEFAULT_INWARD_EFFECT_PADDING_DURATION_MS)
            assertThat(fakeInvocationEffectPreferences.getOutwardAnimationDurationMillis())
                .isEqualTo(DEFAULT_OUTWARD_EFFECT_DURATION_MS)
            assertThat(fakeInvocationEffectPreferences.isInvocationEffectEnabledInPreferences())
                .isEqualTo(DEFAULT_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE)
            assertThat(fakeInvocationEffectPreferences.isCurrentUserAndAssistantPersisted())
                .isTrue()
        }

    private fun createAssistantSettingBundle(
        enableAssistantSetting: Boolean,
        inwardsPaddingDuration: Long,
        outwardsAnimationDuration: Long,
        enableAssistantSetting: Boolean? = null,
        inwardsPaddingDuration: Long? = null,
        outwardsAnimationDuration: Long? = null,
    ) =
        Bundle().apply {
            putString(AssistManager.ACTION_KEY, SET_INVOCATION_EFFECT_PARAMETERS_ACTION)
            putBoolean(IS_INVOCATION_EFFECT_ENABLED_KEY, enableAssistantSetting)
            putLong(INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS, inwardsPaddingDuration)
            putLong(INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS, outwardsAnimationDuration)
            enableAssistantSetting?.let { putBoolean(IS_INVOCATION_EFFECT_ENABLED_KEY, it) }
            inwardsPaddingDuration?.let {
                putLong(INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS, it)
            }
            outwardsAnimationDuration?.let {
                putLong(INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS, it)
            }
        }
}
+66 −60
Original line number Diff line number Diff line
@@ -51,25 +51,27 @@ interface InvocationEffectPreferences {

    val isInvocationEffectEnabledByAssistant: StateFlow<Boolean>

    fun saveCurrentAssistant()

    fun saveCurrentUserId()

    fun setInvocationEffectEnabledByAssistant(enabled: Boolean)

    fun setInwardAnimationPaddingDurationMillis(duration: Long)
    fun isInvocationEffectEnabledInPreferences(): Boolean

    fun getInwardAnimationPaddingDurationMillis(): Long

    fun setOutwardAnimationDurationMillis(duration: Long)

    fun getOutwardAnimationDurationMillis(): Long

    fun isCurrentUserAndAssistantPersisted(): Boolean

    fun setInvocationEffectConfig(config: Config, saveActiveUserAndAssistant: Boolean)

    fun registerOnChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener)

    fun unregisterOnChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener)

    fun dump(pw: PrintWriter, args: Array<out String>)

    data class Config(
        val isEnabled: Boolean,
        val inwardsEffectDurationPadding: Long,
        val outwardsEffectDuration: Long,
    )
}

@SysUISingleton
@@ -81,7 +83,7 @@ constructor(
    private val userRepository: UserRepository,
    roleManager: RoleManager,
    @Background executor: Executor,
    @Background coroutineContext: CoroutineContext,
    @Background private val coroutineContext: CoroutineContext,
) : InvocationEffectPreferences {

    private val sharedPreferences by lazy {
@@ -120,7 +122,8 @@ constructor(
                val changed = activeUser != userId || activeAssistant != assistant
                if (changed) {
                    activeUser = userId
                    activeAssistant = assistant
                    activeAssistant =
                        roleManager.getCurrentAssistantFor(userRepository.selectedUserHandle)
                }
                changed
            }
@@ -152,10 +155,6 @@ constructor(
                initialValue = isInvocationEffectEnabledByAssistant(),
            )

    override fun saveCurrentAssistant() {
        setInPreferences { putString(PERSISTED_FOR_ASSISTANT_PREFERENCE, activeAssistant) }
    }

    private fun getSavedAssistant(): String =
        getOrDefault<String>(
            key = PERSISTED_FOR_ASSISTANT_PREFERENCE,
@@ -163,10 +162,6 @@ constructor(
            checkUserAndAssistant = false,
        )

    override fun saveCurrentUserId() {
        setInPreferences { putInt(PERSISTED_FOR_USER_PREFERENCE, activeUser) }
    }

    private fun getSavedUserId(): Int =
        getOrDefault<Int>(
            key = PERSISTED_FOR_USER_PREFERENCE,
@@ -174,31 +169,8 @@ constructor(
            checkUserAndAssistant = false,
        )

    override fun setInvocationEffectEnabledByAssistant(enabled: Boolean) {
        setInPreferences {
            putBoolean(IS_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE, enabled)
        }
    }

    private fun isInvocationEffectEnabledByAssistant(): Boolean =
        getOrDefault<Boolean>(
            key = IS_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE,
            default = true,
            checkUserAndAssistant = true,
        ) && activeAssistant.isNotEmpty()

    override fun setInwardAnimationPaddingDurationMillis(duration: Long) {
        setInPreferences {
            if (duration in 0..1000) {
                putLong(INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS, duration)
            } else {
                putLong(
                    INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS,
                    DEFAULT_INWARD_EFFECT_PADDING_DURATION_MS,
                )
            }
        }
    }
        isInvocationEffectEnabledInPreferences() && activeAssistant.isNotEmpty()

    override fun getInwardAnimationPaddingDurationMillis(): Long =
        getOrDefault<Long>(
@@ -207,20 +179,6 @@ constructor(
            checkUserAndAssistant = true,
        )

    // TODO(b/418685731): Should we have a positive non-zero min value for out effect duration?
    override fun setOutwardAnimationDurationMillis(duration: Long) {
        setInPreferences {
            if (duration in 0..1000) {
                putLong(INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS, duration)
            } else {
                putLong(
                    INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS,
                    DEFAULT_OUTWARD_EFFECT_DURATION_MS,
                )
            }
        }
    }

    override fun getOutwardAnimationDurationMillis(): Long =
        getOrDefault<Long>(
            key = INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS,
@@ -228,11 +186,59 @@ constructor(
            checkUserAndAssistant = true,
        )

    private fun isCurrentUserAndAssistantPersisted(): Boolean =
    override fun isCurrentUserAndAssistantPersisted(): Boolean =
        activeUser == getSavedUserId() && activeAssistant == getSavedAssistant()

    private fun setInPreferences(block: SharedPreferences.Editor.() -> Unit) {
        bgScope.launch { sharedPreferences.edit { block() } }
    override fun isInvocationEffectEnabledInPreferences(): Boolean =
        getOrDefault<Boolean>(
            key = IS_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE,
            default = DEFAULT_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE,
            checkUserAndAssistant = true,
        )

    override fun setInvocationEffectConfig(
        config: InvocationEffectPreferences.Config,
        saveActiveUserAndAssistant: Boolean,
    ) {
        bgScope.launch(context = coroutineContext) {
            sharedPreferences.edit {
                if (saveActiveUserAndAssistant) {
                    putString(PERSISTED_FOR_ASSISTANT_PREFERENCE, activeAssistant)
                    putInt(PERSISTED_FOR_USER_PREFERENCE, activeUser)
                }

                if (config.isEnabled != isInvocationEffectEnabledInPreferences()) {
                    putBoolean(
                        IS_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE,
                        config.isEnabled,
                    )
                }

                if (
                    config.inwardsEffectDurationPadding != getInwardAnimationPaddingDurationMillis()
                ) {
                    putLong(
                        INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS,
                        if (config.inwardsEffectDurationPadding in 0..1000) {
                            config.inwardsEffectDurationPadding
                        } else {
                            DEFAULT_INWARD_EFFECT_PADDING_DURATION_MS
                        },
                    )
                }

                if (config.outwardsEffectDuration != getOutwardAnimationDurationMillis()) {
                    putLong(
                        INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS,
                        if (config.outwardsEffectDuration in 100..1000) {
                            config.outwardsEffectDuration
                        } else {
                            DEFAULT_OUTWARD_EFFECT_DURATION_MS
                        },
                    )
                }
            }
        }
    }

    private inline fun <reified T> getOrDefault(
+43 −32
Original line number Diff line number Diff line
@@ -29,9 +29,6 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.shared.Flags
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.DEFAULT_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.DEFAULT_INWARD_EFFECT_PADDING_DURATION_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.DEFAULT_OUTWARD_EFFECT_DURATION_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.IS_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE
@@ -91,43 +88,57 @@ constructor(
        return preferences.getOutwardAnimationDurationMillis()
    }

    private fun setInvocationEffectPreferences(
        isEnabled: Boolean? = null,
        inwardsEffectDurationPadding: Long? = null,
        outwardsEffectDuration: Long? = null,
    ) {

        preferences.setInvocationEffectConfig(
            config =
                InvocationEffectPreferences.Config(
                    isEnabled = isEnabled ?: preferences.isInvocationEffectEnabledInPreferences(),
                    inwardsEffectDurationPadding =
                        inwardsEffectDurationPadding
                            ?: preferences.getInwardAnimationPaddingDurationMillis(),
                    outwardsEffectDuration =
                        outwardsEffectDuration ?: preferences.getOutwardAnimationDurationMillis(),
                ),
            saveActiveUserAndAssistant = !preferences.isCurrentUserAndAssistantPersisted(),
        )
    }

    override fun tryHandleSetUiHints(hints: Bundle): Boolean {
        return when (hints.getString(AssistManager.ACTION_KEY)) {
            SET_INVOCATION_EFFECT_PARAMETERS_ACTION -> {

                preferences.saveCurrentUserId()
                preferences.saveCurrentAssistant()

                val isEnabled: Boolean? =
                    if (hints.containsKey(IS_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE)) {
                    preferences.setInvocationEffectEnabledByAssistant(
                        hints.getBoolean(IS_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE)
                    )
                    } else {
                    preferences.setInvocationEffectEnabledByAssistant(
                        DEFAULT_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE
                    )
                        null
                    }

                val inwardsEffectDurationPadding: Long? =
                    if (hints.containsKey(INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS)) {
                    preferences.setInwardAnimationPaddingDurationMillis(
                        hints.getLong(INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS)
                    )
                    } else {
                    preferences.setInwardAnimationPaddingDurationMillis(
                        DEFAULT_INWARD_EFFECT_PADDING_DURATION_MS
                    )
                        null
                    }

                val outwardsEffectDuration: Long? =
                    if (hints.containsKey(INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS)) {
                    preferences.setOutwardAnimationDurationMillis(
                        hints.getLong(INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS)
                    )
                    } else {
                    preferences.setOutwardAnimationDurationMillis(
                        DEFAULT_OUTWARD_EFFECT_DURATION_MS
                    )
                        null
                    }

                setInvocationEffectPreferences(
                    isEnabled = isEnabled,
                    inwardsEffectDurationPadding = inwardsEffectDurationPadding,
                    outwardsEffectDuration = outwardsEffectDuration,
                )

                true
            }
            else -> false
+38 −24
Original line number Diff line number Diff line
@@ -19,10 +19,12 @@ package com.android.systemui.topwindoweffects.data.repository
import android.content.SharedPreferences
import androidx.core.content.edit
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.DEFAULT_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.DEFAULT_INWARD_EFFECT_PADDING_DURATION_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.DEFAULT_OUTWARD_EFFECT_DURATION_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.IS_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.PERSISTED_FOR_ASSISTANT_PREFERENCE
import com.android.systemui.topwindoweffects.data.repository.InvocationEffectPreferencesImpl.Companion.PERSISTED_FOR_USER_PREFERENCE
import java.io.PrintWriter
@@ -42,35 +44,23 @@ class FakeInvocationEffectPreferences : InvocationEffectPreferences {
        fakeSharedPreferences.edit { f() }
    }

    fun clear() {
        fakeSharedPreferences = FakeSharedPreferences()
    override fun isInvocationEffectEnabledInPreferences(): Boolean {
        return fakeSharedPreferences.getBoolean(
            IS_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE,
            DEFAULT_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE,
        )
    }

    override fun saveCurrentAssistant() {
        addToPref { putString(PERSISTED_FOR_ASSISTANT_PREFERENCE, activeAssistant) }
    fun clear() {
        fakeSharedPreferences = FakeSharedPreferences()
    }

    fun getSavedAssistant(): String {
        return fakeSharedPreferences.getString(PERSISTED_FOR_ASSISTANT_PREFERENCE, "") ?: ""
    }

    override fun saveCurrentUserId() {
        addToPref { putInt(PERSISTED_FOR_USER_PREFERENCE, activeUserId) }
    }

    fun getSavedUserId(): Int {
        return fakeSharedPreferences.getInt(PERSISTED_FOR_USER_PREFERENCE, -1)
    }

    fun isActiveUserAndAssistantPersisted() =
        activeUserId == getSavedUserId() && activeAssistant == getSavedAssistant()

    override fun setInvocationEffectEnabledByAssistant(enabled: Boolean) {
        isInvocationEffectEnabledByAssistant.value = enabled
    }

    override fun setInwardAnimationPaddingDurationMillis(duration: Long) {
        addToPref { putLong(INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS, duration) }
        return fakeSharedPreferences.getInt(PERSISTED_FOR_USER_PREFERENCE, Int.MIN_VALUE)
    }

    override fun getInwardAnimationPaddingDurationMillis(): Long {
@@ -80,10 +70,6 @@ class FakeInvocationEffectPreferences : InvocationEffectPreferences {
        )
    }

    override fun setOutwardAnimationDurationMillis(duration: Long) {
        addToPref { putLong(INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS, duration) }
    }

    override fun getOutwardAnimationDurationMillis(): Long {
        return fakeSharedPreferences.getLong(
            INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS,
@@ -91,6 +77,30 @@ class FakeInvocationEffectPreferences : InvocationEffectPreferences {
        )
    }

    override fun isCurrentUserAndAssistantPersisted(): Boolean {
        return activeUserId == getSavedUserId() && activeAssistant == getSavedAssistant()
    }

    override fun setInvocationEffectConfig(
        config: InvocationEffectPreferences.Config,
        saveActiveUserAndAssistant: Boolean,
    ) {
        if (saveActiveUserAndAssistant) {
            addToPref {
                putString(PERSISTED_FOR_ASSISTANT_PREFERENCE, activeAssistant)
                putInt(PERSISTED_FOR_USER_PREFERENCE, activeUserId)
            }
        }
        addToPref {
            putLong(INVOCATION_EFFECT_ANIMATION_OUT_DURATION_MS, config.outwardsEffectDuration)
            putLong(
                INVOCATION_EFFECT_ANIMATION_IN_DURATION_PADDING_MS,
                config.inwardsEffectDurationPadding,
            )
            putBoolean(IS_INVOCATION_EFFECT_ENABLED_BY_ASSISTANT_PREFERENCE, config.isEnabled)
        }
    }

    override fun registerOnChangeListener(
        listener: SharedPreferences.OnSharedPreferenceChangeListener
    ) {
@@ -106,6 +116,10 @@ class FakeInvocationEffectPreferences : InvocationEffectPreferences {
    override fun dump(pw: PrintWriter, args: Array<out String>) {
        // empty
    }

    fun setInvocationEffectEnabledByAssistant(enabled: Boolean) {
        isInvocationEffectEnabledByAssistant.value = enabled
    }
}

private class FakeSharedPreferences : SharedPreferences {