1 /*
2  * 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 package com.android.settings.display
17 
18 import android.content.Context
19 import android.os.UserManager
20 import android.provider.Settings
21 import android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
22 import android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL
23 import androidx.preference.Preference
24 import com.android.settings.PreferenceRestrictionMixin
25 import com.android.settings.R
26 import com.android.settings.flags.Flags
27 import com.android.settingslib.PrimarySwitchPreference
28 import com.android.settingslib.datastore.KeyValueStore
29 import com.android.settingslib.datastore.KeyedObservableDelegate
30 import com.android.settingslib.datastore.SettingsStore
31 import com.android.settingslib.datastore.SettingsSystemStore
32 import com.android.settingslib.metadata.BooleanValue
33 import com.android.settingslib.metadata.PersistentPreference
34 import com.android.settingslib.metadata.PreferenceAvailabilityProvider
35 import com.android.settingslib.metadata.PreferenceMetadata
36 import com.android.settingslib.metadata.ProvidePreferenceScreen
37 import com.android.settingslib.metadata.ReadWritePermit
38 import com.android.settingslib.metadata.SensitivityLevel
39 import com.android.settingslib.metadata.preferenceHierarchy
40 import com.android.settingslib.preference.PreferenceScreenBinding
41 import com.android.settingslib.preference.PreferenceScreenCreator
42 
43 @ProvidePreferenceScreen
44 class AutoBrightnessScreen :
45     PreferenceScreenCreator,
46     PreferenceScreenBinding,
47     PreferenceAvailabilityProvider,
48     PreferenceRestrictionMixin,
49     PersistentPreference<Boolean>,
50     BooleanValue {
51     override val key: String
52         get() = KEY
53 
54     override val title: Int
55         get() = R.string.auto_brightness_title
56 
isFlagEnablednull57     override fun isFlagEnabled(context: Context) = Flags.catalystScreenBrightnessMode()
58 
59     override fun fragmentClass() = AutoBrightnessSettings::class.java
60 
61     override fun hasCompleteHierarchy() = false
62 
63     override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
64 
storagenull65     override fun storage(context: Context): KeyValueStore =
66         AutoBrightnessDataStore(SettingsSystemStore.get(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     override fun isAvailable(context: Context) =
78         context.resources.getBoolean(
79             com.android.internal.R.bool.config_automatic_brightness_available
80         )
81 
82     override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context)
83 
84     override val restrictionKeys
85         get() = arrayOf(UserManager.DISALLOW_CONFIG_BRIGHTNESS)
86 
87     override val useAdminDisabledSummary: Boolean
88         get() = true
89 
90     override fun createWidget(context: Context) = PrimarySwitchPreference(context)
91 
92     override fun bind(preference: Preference, metadata: PreferenceMetadata) {
93         super.bind(preference, metadata)
94         (preference as PrimarySwitchPreference).apply {
95             isSwitchEnabled = isEnabled
96             // "true" is not the real default value (it is provided by AutoBrightnessDataStore)
97             isChecked = preferenceDataStore!!.getBoolean(key, true)
98         }
99     }
100 
101     /**
102      * The datastore for brightness, which is persisted as integer but the external type is boolean.
103      */
104     @Suppress("UNCHECKED_CAST")
105     private class AutoBrightnessDataStore(private val settingsStore: SettingsStore) :
106         KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
107 
containsnull108         override fun contains(key: String) = settingsStore.contains(key)
109 
110         override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
111             DEFAULT_VALUE.toBoolean() as T
112 
113         override fun <T : Any> getValue(key: String, valueType: Class<T>) =
114             (settingsStore.getInt(key) ?: DEFAULT_VALUE).toBoolean() as T
115 
116         override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
117             settingsStore.setInt(key, (value as? Boolean)?.toBrightnessMode())
118 
119         /** Converts brightness mode integer to boolean. */
120         private fun Int.toBoolean() = this == SCREEN_BRIGHTNESS_MODE_AUTOMATIC
121 
122         /** Converts boolean value to brightness mode integer. */
123         private fun Boolean.toBrightnessMode() =
124             if (this) SCREEN_BRIGHTNESS_MODE_AUTOMATIC else SCREEN_BRIGHTNESS_MODE_MANUAL
125     }
126 
127     companion object {
128         const val KEY = Settings.System.SCREEN_BRIGHTNESS_MODE
129         private const val DEFAULT_VALUE = SCREEN_BRIGHTNESS_MODE_MANUAL
130     }
131 }
132