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

Commit 8e73d0f5 authored by Jacky Wang's avatar Jacky Wang
Browse files

[Catalyst] Update RemoveAnimationsPreference

Bug: 373451690
Flag: com.android.settings.flags.catalyst_accessibility_color_and_motion
Test: atest & devtool
Change-Id: Id648febf32bebb391f1277e28f58ddb0d5130d59
parent 851bf187
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@
    <SwitchPreferenceCompat
        android:icon="@drawable/ic_accessibility_animation"
        android:key="animator_duration_scale"
        android:persistent="false"
        android:summary="@string/accessibility_disable_animations_summary"
        android:title="@string/accessibility_disable_animations"
        settings:controller="com.android.settings.accessibility.DisableAnimationsPreferenceController"/>
+1 −2
Original line number Diff line number Diff line
@@ -50,7 +50,6 @@ public class ColorAndMotionFragment extends DashboardFragment {

    // Preferences
    private static final String DISPLAY_DALTONIZER_PREFERENCE_SCREEN = "daltonizer_preference";
    private static final String TOGGLE_DISABLE_ANIMATIONS = "toggle_disable_animations";
    private static final String TOGGLE_LARGE_POINTER_ICON = "toggle_large_pointer_icon";
    @VisibleForTesting
    static final String TOGGLE_FORCE_INVERT = "toggle_force_invert";
@@ -125,7 +124,7 @@ public class ColorAndMotionFragment extends DashboardFragment {
        mDisplayDaltonizerPreferenceScreen = findPreference(DISPLAY_DALTONIZER_PREFERENCE_SCREEN);

        // Disable animation.
        mToggleDisableAnimationsPreference = findPreference(TOGGLE_DISABLE_ANIMATIONS);
        mToggleDisableAnimationsPreference = findPreference(RemoveAnimationsPreference.KEY);

        // Large pointer icon.
        mToggleLargePointerIconPreference = findPreference(TOGGLE_LARGE_POINTER_ICON);
+34 −27
Original line number Diff line number Diff line
@@ -27,45 +27,50 @@ import com.android.settingslib.datastore.NoOpKeyedObservable
import com.android.settingslib.datastore.SettingsGlobalStore
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.ReadWritePermit
import com.android.settingslib.metadata.SwitchPreference
import com.android.settingslib.preference.SwitchPreferenceBinding

class RemoveAnimationsPreference :
    SwitchPreference(
        KEY,
        R.string.accessibility_disable_animations,
        R.string.accessibility_disable_animations_summary
        R.string.accessibility_disable_animations_summary,
    ),
    SwitchPreferenceBinding,
    PreferenceLifecycleProvider {

    private var mSettingsKeyedObserver: KeyedObserver<String?>? = null
    private var mSettingsKeyedObserver: KeyedObserver<String>? = null

    override val icon: Int
        @DrawableRes get() = R.drawable.ic_accessibility_animation

    override fun onStart(context: PreferenceLifecycleContext) {
        mSettingsKeyedObserver = object : KeyedObserver<String?> {
            override fun onKeyChanged(key: String?, reason: Int) {
                context.notifyPreferenceChange(KEY)
            }
        }
        mSettingsKeyedObserver?.let {
            for (key in TOGGLE_ANIMATION_KEYS) {
                SettingsGlobalStore.get(context).addObserver(key, it, HandlerExecutor.main)
            }
        val observer = KeyedObserver<String> { _, _ -> context.notifyPreferenceChange(KEY) }
        mSettingsKeyedObserver = observer
        val storage = SettingsGlobalStore.get(context)
        for (key in getAnimationKeys()) {
            storage.addObserver(key, observer, HandlerExecutor.main)
        }
    }

    override fun onStop(context: PreferenceLifecycleContext) {
        mSettingsKeyedObserver?.let {
            SettingsGlobalStore.get(context).removeObserver(it)
            val storage = SettingsGlobalStore.get(context)
            for (key in getAnimationKeys()) {
                storage.removeObserver(key, it)
            }
            mSettingsKeyedObserver = null
        }
    }

    override fun storage(context: Context): KeyValueStore = RemoveAnimationsStorage(context)

    override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) =
        ReadWritePermit.ALLOW

    override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
        ReadWritePermit.ALLOW

    @Suppress("UNCHECKED_CAST")
    private class RemoveAnimationsStorage(private val context: Context) :
        NoOpKeyedObservable<String>(), KeyValueStore {
        override fun contains(key: String) = key == KEY
@@ -74,7 +79,6 @@ class RemoveAnimationsPreference :
            when {
                key == KEY && valueType == Boolean::class.javaObjectType ->
                    !isAnimationEnabled(context) as T

                else -> null
            }

@@ -94,16 +98,11 @@ class RemoveAnimationsPreference :
        const val ANIMATION_ON_VALUE: Float = 1.0f
        const val ANIMATION_OFF_VALUE: Float = 0.0f

        val TOGGLE_ANIMATION_KEYS: List<String> = listOf(
            Settings.Global.WINDOW_ANIMATION_SCALE, Settings.Global.TRANSITION_ANIMATION_SCALE,
            Settings.Global.ANIMATOR_DURATION_SCALE
        )

        fun isAnimationEnabled(context: Context): Boolean {
            val storage = SettingsGlobalStore.get(context)
            // This pref treats animation as enabled if *any* of the animation types are enabled.
            for (animationSetting in TOGGLE_ANIMATION_KEYS) {
                val animationValue: Float? =
                    SettingsGlobalStore.get(context).getFloat(animationSetting)
            for (animationSetting in getAnimationKeys()) {
                val animationValue: Float? = storage.getFloat(animationSetting)
                // Animation is enabled by default, so treat null as enabled.
                if (animationValue == null || animationValue > ANIMATION_OFF_VALUE) {
                    return true
@@ -113,10 +112,18 @@ class RemoveAnimationsPreference :
        }

        fun setAnimationEnabled(context: Context, enabled: Boolean) {
            val value = if (enabled) ANIMATION_ON_VALUE else ANIMATION_OFF_VALUE;
            for (animationSetting in TOGGLE_ANIMATION_KEYS) {
                SettingsGlobalStore.get(context).setFloat(animationSetting, value)
            val storage = SettingsGlobalStore.get(context)
            val value = if (enabled) ANIMATION_ON_VALUE else ANIMATION_OFF_VALUE
            for (animationSetting in getAnimationKeys()) {
                storage.setFloat(animationSetting, value)
            }
        }

        fun getAnimationKeys() =
            listOf(
                Settings.Global.WINDOW_ANIMATION_SCALE,
                Settings.Global.TRANSITION_ANIMATION_SCALE,
                Settings.Global.ANIMATOR_DURATION_SCALE,
            )
    }
}
+26 −19
Original line number Diff line number Diff line
@@ -20,10 +20,11 @@ import android.content.Context
import androidx.preference.SwitchPreferenceCompat
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settings.accessibility.RemoveAnimationsPreference.Companion.ANIMATION_ON_VALUE
import com.android.settings.accessibility.RemoveAnimationsPreference.Companion.TOGGLE_ANIMATION_KEYS
import com.android.settingslib.datastore.SettingsGlobalStore
import com.android.settingslib.preference.createAndBindWidget
import com.android.settingslib.preference.PreferenceScreenBindingHelper
import com.android.settingslib.preference.PreferenceScreenFactory
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@@ -33,53 +34,59 @@ class RemoveAnimationsPreferenceTest {

    private val appContext: Context = ApplicationProvider.getApplicationContext()

    private val removeAnimationsPreference =
        RemoveAnimationsPreference()

    private fun getSwitchPreferenceCompat(): SwitchPreferenceCompat =
        removeAnimationsPreference.createAndBindWidget(appContext)
    private fun getRemoveAnimationsSwitchPreference(): SwitchPreferenceCompat =
        PreferenceScreenFactory(appContext).let {
            val preferenceScreen = it.inflate(R.xml.accessibility_color_and_motion)!!
            it.preferenceManager.setPreferences(preferenceScreen)
            PreferenceScreenBindingHelper.bind(preferenceScreen)
            preferenceScreen.findPreference(RemoveAnimationsPreference.KEY)!!
        }

    @Test
    fun animationOff_switchPreferenceIsChecked() {
        RemoveAnimationsPreference.setAnimationEnabled(appContext, false)

        assertThat(getSwitchPreferenceCompat().isChecked).isTrue()
        assertThat(getRemoveAnimationsSwitchPreference().isChecked).isTrue()
    }

    @Test
    fun animationOn_switchPreferenceIsNotChecked() {
        RemoveAnimationsPreference.setAnimationEnabled(appContext, true)

        assertThat(getSwitchPreferenceCompat().isChecked).isFalse()
        assertThat(getRemoveAnimationsSwitchPreference().isChecked).isFalse()
    }

    @Test
    fun oneAnimationValueOn_switchPreferenceIsNotChecked() {
        // Animation is disabled, except for one value.
        RemoveAnimationsPreference.setAnimationEnabled(appContext, false)
        SettingsGlobalStore.get(appContext).setFloat(TOGGLE_ANIMATION_KEYS[0], ANIMATION_ON_VALUE)
        SettingsGlobalStore.get(appContext)
            .setFloat(RemoveAnimationsPreference.getAnimationKeys()[0], ANIMATION_ON_VALUE)

        assertThat(getSwitchPreferenceCompat().isChecked).isFalse()
        assertThat(getRemoveAnimationsSwitchPreference().isChecked).isFalse()
    }

    @Test
    fun storageSetTrue_turnsOffAnimation() {
    fun toggleOnSwitch_turnsOffAnimation() {
        RemoveAnimationsPreference.setAnimationEnabled(appContext, true)

        storageSetValue(true)
        val switchPreference = getRemoveAnimationsSwitchPreference()
        assertThat(switchPreference.isChecked).isFalse()
        switchPreference.performClick()
        assertThat(switchPreference.isChecked).isTrue()

        assertThat(RemoveAnimationsPreference.isAnimationEnabled(appContext)).isFalse()
    }

    @Test
    fun storageSetFalse_turnsOnAnimation() {
    fun toggleOffSwitch_turnsOnAnimation() {
        RemoveAnimationsPreference.setAnimationEnabled(appContext, false)

        storageSetValue(false)
        val switchPreference = getRemoveAnimationsSwitchPreference()
        assertThat(switchPreference.isChecked).isTrue()
        switchPreference.performClick()
        assertThat(switchPreference.isChecked).isFalse()

        assertThat(RemoveAnimationsPreference.isAnimationEnabled(appContext)).isTrue()
    }

    private fun storageSetValue(enabled: Boolean) = removeAnimationsPreference.storage(appContext)
        .setValue(RemoveAnimationsPreference.KEY, Boolean::class.javaObjectType, enabled)
}