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