1 /* <lambda>null2 * Copyright (C) 2024 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 17 package com.android.settings.accessibility 18 19 import android.annotation.DrawableRes 20 import android.content.Context 21 import android.provider.Settings 22 import com.android.settings.R 23 import com.android.settingslib.datastore.HandlerExecutor 24 import com.android.settingslib.datastore.KeyValueStore 25 import com.android.settingslib.datastore.KeyedObserver 26 import com.android.settingslib.datastore.NoOpKeyedObservable 27 import com.android.settingslib.datastore.SettingsGlobalStore 28 import com.android.settingslib.metadata.PreferenceLifecycleContext 29 import com.android.settingslib.metadata.PreferenceLifecycleProvider 30 import com.android.settingslib.metadata.ReadWritePermit 31 import com.android.settingslib.metadata.SensitivityLevel 32 import com.android.settingslib.metadata.SwitchPreference 33 34 class RemoveAnimationsPreference : 35 SwitchPreference( 36 KEY, 37 R.string.accessibility_disable_animations, 38 R.string.accessibility_disable_animations_summary, 39 ), 40 PreferenceLifecycleProvider { 41 42 private var mSettingsKeyedObserver: KeyedObserver<String>? = null 43 44 override val icon: Int 45 @DrawableRes get() = R.drawable.ic_accessibility_animation 46 47 override fun onStart(context: PreferenceLifecycleContext) { 48 val observer = KeyedObserver<String> { _, _ -> context.notifyPreferenceChange(KEY) } 49 mSettingsKeyedObserver = observer 50 val storage = SettingsGlobalStore.get(context) 51 for (key in getAnimationKeys()) { 52 storage.addObserver(key, observer, HandlerExecutor.main) 53 } 54 } 55 56 override fun onStop(context: PreferenceLifecycleContext) { 57 mSettingsKeyedObserver?.let { 58 val storage = SettingsGlobalStore.get(context) 59 for (key in getAnimationKeys()) { 60 storage.removeObserver(key, it) 61 } 62 mSettingsKeyedObserver = null 63 } 64 } 65 66 override fun storage(context: Context): KeyValueStore = RemoveAnimationsStorage(context) 67 68 override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) = 69 ReadWritePermit.ALLOW 70 71 override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) = 72 ReadWritePermit.ALLOW 73 74 override val sensitivityLevel 75 get() = SensitivityLevel.NO_SENSITIVITY 76 77 @Suppress("UNCHECKED_CAST") 78 private class RemoveAnimationsStorage(private val context: Context) : 79 NoOpKeyedObservable<String>(), KeyValueStore { 80 override fun contains(key: String) = key == KEY 81 82 override fun <T : Any> getValue(key: String, valueType: Class<T>) = 83 when { 84 key == KEY && valueType == Boolean::class.javaObjectType -> 85 !isAnimationEnabled(context) as T 86 else -> null 87 } 88 89 override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) { 90 if (key == KEY && value is Boolean) { 91 setAnimationEnabled(context, !value) 92 } 93 } 94 } 95 96 companion object { 97 // This KEY must match the key used in accessibility_color_and_motion.xml for this 98 // preference, at least until the entire screen is migrated to Catalyst and that XML 99 // is deleted. Use any key from the set of 3 toggle animation keys. 100 const val KEY = Settings.Global.ANIMATOR_DURATION_SCALE 101 102 const val ANIMATION_ON_VALUE: Float = 1.0f 103 const val ANIMATION_OFF_VALUE: Float = 0.0f 104 105 fun isAnimationEnabled(context: Context): Boolean { 106 val storage = SettingsGlobalStore.get(context) 107 // This pref treats animation as enabled if *any* of the animation types are enabled. 108 for (animationSetting in getAnimationKeys()) { 109 val animationValue: Float? = storage.getFloat(animationSetting) 110 // Animation is enabled by default, so treat null as enabled. 111 if (animationValue == null || animationValue > ANIMATION_OFF_VALUE) { 112 return true 113 } 114 } 115 return false 116 } 117 118 fun setAnimationEnabled(context: Context, enabled: Boolean) { 119 val storage = SettingsGlobalStore.get(context) 120 val value = if (enabled) ANIMATION_ON_VALUE else ANIMATION_OFF_VALUE 121 for (animationSetting in getAnimationKeys()) { 122 storage.setFloat(animationSetting, value) 123 } 124 } 125 126 fun getAnimationKeys() = 127 listOf( 128 Settings.Global.WINDOW_ANIMATION_SCALE, 129 Settings.Global.TRANSITION_ANIMATION_SCALE, 130 Settings.Global.ANIMATOR_DURATION_SCALE, 131 ) 132 } 133 } 134