From 369263156bc3d041a635c201d2db7d1f02d9eb1b Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Tue, 22 Oct 2024 11:25:28 +0800 Subject: [PATCH 1/2] [Catalyst] Migrate Adaptive brightness in the DisplayScreen Migrate the AutoBrightnessPreferenceController to be a Catalyst type preference. Test: atest AutoBrightnessScreenTest Bug: 374712065 Flag: com.android.settings.flags.catalyst_screen_brightness_mode Change-Id: I80d17a4f7fae237825ab84d1f428614affcb9065 --- aconfig/catalyst/display.aconfig | 6 + res/xml/display_settings.xml | 2 +- .../AutoBrightnessPreferenceController.java | 2 + .../settings/display/AutoBrightnessScreen.kt | 100 +++++++++++++ .../android/settings/display/DisplayScreen.kt | 1 + ...utoBrightnessPreferenceControllerTest.java | 2 + .../display/AutoBrightnessScreenTest.kt | 140 ++++++++++++++++++ 7 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/display/AutoBrightnessScreen.kt create mode 100644 tests/robotests/src/com/android/settings/display/AutoBrightnessScreenTest.kt diff --git a/aconfig/catalyst/display.aconfig b/aconfig/catalyst/display.aconfig index 038a9b0c632..9485e70fc1d 100644 --- a/aconfig/catalyst/display.aconfig +++ b/aconfig/catalyst/display.aconfig @@ -22,3 +22,9 @@ flag { bug: "323791114" } +flag { + name: "catalyst_screen_brightness_mode" + namespace: "android_settings" + description: "Flag for Adaptive brightness" + bug: "323791114" +} diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml index c7e29675757..3baf439035a 100644 --- a/res/xml/display_settings.xml +++ b/res/xml/display_settings.xml @@ -34,7 +34,7 @@ settings:userRestriction="no_config_brightness"/> , + BooleanValue { + override val key: String + get() = KEY + + override val title: Int + get() = R.string.auto_brightness_title + + override fun isFlagEnabled(context: Context) = Flags.catalystScreenBrightnessMode() + + override fun fragmentClass() = AutoBrightnessSettings::class.java + + override fun hasCompleteHierarchy() = false + + override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {} + + override fun storage(context: Context) = SettingsSystemStore.get(context) + + override fun isAvailable(context: Context) = + context.resources.getBoolean( + com.android.internal.R.bool.config_automatic_brightness_available + ) + + override fun isEnabled(context: Context) = + !UserManager.get(context) + .hasBaseUserRestriction(UserManager.DISALLOW_CONFIG_BRIGHTNESS, Process.myUserHandle()) + + override fun isRestricted(context: Context) = + RestrictedLockUtilsInternal.checkIfRestrictionEnforced( + context, + UserManager.DISALLOW_CONFIG_BRIGHTNESS, + UserHandle.myUserId(), + ) != null + + override fun createWidget(context: Context) = PrimarySwitchPreference(context) + + override fun bind(preference: Preference, metadata: PreferenceMetadata) { + super.bind(preference, metadata) + (preference as PrimarySwitchPreference).apply { + useAdminDisabledSummary(true) + isSwitchEnabled = isEnabled + isChecked = + storage(preference.context).getBoolean(KEY) + ?: getDefault(SCREEN_BRIGHTNESS_MODE_MANUAL) + } + } + + private fun getDefault(brightnessDefault: Int): Boolean = + brightnessDefault == SCREEN_BRIGHTNESS_MODE_AUTOMATIC + + companion object { + const val KEY = Settings.System.SCREEN_BRIGHTNESS_MODE + } +} diff --git a/src/com/android/settings/display/DisplayScreen.kt b/src/com/android/settings/display/DisplayScreen.kt index 5248367a856..b1a822d8932 100644 --- a/src/com/android/settings/display/DisplayScreen.kt +++ b/src/com/android/settings/display/DisplayScreen.kt @@ -52,6 +52,7 @@ class DisplayScreen : override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) { +BrightnessLevelRestrictedPreference() + +AutoBrightnessScreen.KEY +DarkModeScreen.KEY +PeakRefreshRateSwitchPreference() } diff --git a/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerTest.java index 0122044f13c..902de787334 100644 --- a/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerTest.java @@ -43,6 +43,7 @@ import org.robolectric.annotation.Config; /** * Tests for {@link AutoBrightnessPreferenceController}. */ +// LINT.IfChange @RunWith(RobolectricTestRunner.class) @Config(shadows = {SettingsShadowResources.class}) public class AutoBrightnessPreferenceControllerTest { @@ -139,3 +140,4 @@ public class AutoBrightnessPreferenceControllerTest { assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } } +// LINT.ThenChange(AutoBrightnessScreenTest.kt) diff --git a/tests/robotests/src/com/android/settings/display/AutoBrightnessScreenTest.kt b/tests/robotests/src/com/android/settings/display/AutoBrightnessScreenTest.kt new file mode 100644 index 00000000000..c7f78cd82ec --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/AutoBrightnessScreenTest.kt @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.display + +import android.content.Context +import android.provider.Settings +import android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC +import android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL +import android.view.LayoutInflater +import androidx.preference.PreferenceViewHolder +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.testutils.shadow.SettingsShadowResources +import com.android.settingslib.PrimarySwitchPreference +import com.android.settingslib.widget.SettingsThemeHelper.isExpressiveTheme +import com.android.settingslib.widget.theme.R +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.annotation.Config + +// LINT.IfChange +@RunWith(AndroidJUnit4::class) +@Config(shadows = [SettingsShadowResources::class]) +class AutoBrightnessScreenTest { + + private val context: Context = ApplicationProvider.getApplicationContext() + + private val preferenceScreenCreator = AutoBrightnessScreen() + + @Test + fun switchClick_defaultScreenBrightnessModeTurnOffAuto_returnTrue() { + setScreenBrightnessMode(SCREEN_BRIGHTNESS_MODE_MANUAL) + val preference = getPrimarySwitchPreference() + + assertThat(preference.switch.isChecked).isFalse() + + preference.switch.performClick() + + assertThat(preference.isChecked).isTrue() + } + + @Test + fun switchClick_defaultScreenBrightnessModeTurnOnAuto_returnFalse() { + setScreenBrightnessMode(SCREEN_BRIGHTNESS_MODE_AUTOMATIC) + val preference = getPrimarySwitchPreference() + + assertThat(preference.switch.isChecked).isTrue() + + preference.switch.performClick() + + assertThat(preference.isChecked).isFalse() + } + + @Test + fun setChecked_updatesCorrectly() { + val preference = getPrimarySwitchPreference() + + preference.isChecked = true + + assertThat(preference.switch.isChecked).isTrue() + + preference.isChecked = false + + assertThat(preference.switch.isChecked).isFalse() + } + + @Test + fun isChecked_defaultScreenBrightnessModeTurnOffAuto_returnFalse() { + setScreenBrightnessMode(SCREEN_BRIGHTNESS_MODE_MANUAL) + + val preference = getPrimarySwitchPreference() + + assertThat(preference.isChecked).isFalse() + } + + @Test + fun isChecked_defaultScreenBrightnessModeTurnOffAuto_returnTrue() { + setScreenBrightnessMode(SCREEN_BRIGHTNESS_MODE_AUTOMATIC) + + val preference = getPrimarySwitchPreference() + + assertThat(preference.isChecked).isTrue() + } + + @Test + fun isAvailable_configTrueSet_shouldReturnTrue() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_automatic_brightness_available, + true, + ) + + assertThat(preferenceScreenCreator.isAvailable(context)).isTrue() + } + + @Test + fun isAvailable_configFalseSet_shouldReturnFalse() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_automatic_brightness_available, + false, + ) + + assertThat(preferenceScreenCreator.isAvailable(context)).isFalse() + } + + private fun getPrimarySwitchPreference(): PrimarySwitchPreference = + preferenceScreenCreator.run { + val preference = createWidget(context) + bind(preference, this) + val holder = + PreferenceViewHolder.createInstanceForTests( + LayoutInflater.from(context).inflate(getResId(), /* root= */ null) + ) + .apply { findViewById(androidx.preference.R.id.switchWidget) } + preference.apply { onBindViewHolder(holder) } + } + + private fun setScreenBrightnessMode(value: Int) = + Settings.System.putInt(context.contentResolver, AutoBrightnessScreen.KEY, value) + + private fun getResId() = + when { + isExpressiveTheme(context) -> R.layout.settingslib_expressive_preference_switch + else -> androidx.preference.R.layout.preference_widget_switch_compat + } +} +// LINT.ThenChange(AutoBrightnessPreferenceControllerTest.java) From 45f5ef607d5dcc0320caf750f87afbd625f8d6ea Mon Sep 17 00:00:00 2001 From: Jacky Wang Date: Sun, 3 Nov 2024 12:31:45 +0800 Subject: [PATCH 2/2] [Catalyst] Proivde KeyValueStore for "Adaptive brightness" NO_IFTTT=Ignore test Bug: 374712065 Flag: com.android.settings.flags.catalyst_screen_brightness_mode Test: adb shell settings delete/get/put system screen_brightness_mode Change-Id: I57b72082853493173648d4658d2f225121f68bbf --- .../settings/display/AutoBrightnessScreen.kt | 39 ++++++++++++++++--- .../display/AutoBrightnessScreenTest.kt | 2 + 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/display/AutoBrightnessScreen.kt b/src/com/android/settings/display/AutoBrightnessScreen.kt index 44a48dc87a6..2e8c7088ae9 100644 --- a/src/com/android/settings/display/AutoBrightnessScreen.kt +++ b/src/com/android/settings/display/AutoBrightnessScreen.kt @@ -27,6 +27,9 @@ import com.android.settings.R import com.android.settings.flags.Flags import com.android.settingslib.PrimarySwitchPreference import com.android.settingslib.RestrictedLockUtilsInternal +import com.android.settingslib.datastore.KeyValueStore +import com.android.settingslib.datastore.KeyedObservableDelegate +import com.android.settingslib.datastore.SettingsStore import com.android.settingslib.datastore.SettingsSystemStore import com.android.settingslib.metadata.BooleanValue import com.android.settingslib.metadata.PersistentPreference @@ -60,7 +63,8 @@ class AutoBrightnessScreen : override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {} - override fun storage(context: Context) = SettingsSystemStore.get(context) + override fun storage(context: Context): KeyValueStore = + AutoBrightnessDataStore(SettingsSystemStore.get(context)) override fun isAvailable(context: Context) = context.resources.getBoolean( @@ -85,16 +89,39 @@ class AutoBrightnessScreen : (preference as PrimarySwitchPreference).apply { useAdminDisabledSummary(true) isSwitchEnabled = isEnabled - isChecked = - storage(preference.context).getBoolean(KEY) - ?: getDefault(SCREEN_BRIGHTNESS_MODE_MANUAL) + // "true" is not the real default value (it is provided by AutoBrightnessDataStore) + isChecked = preferenceDataStore!!.getBoolean(key, true) } } - private fun getDefault(brightnessDefault: Int): Boolean = - brightnessDefault == SCREEN_BRIGHTNESS_MODE_AUTOMATIC + /** + * The datastore for brightness, which is persisted as integer but the external type is boolean. + */ + @Suppress("UNCHECKED_CAST") + private class AutoBrightnessDataStore(private val settingsStore: SettingsStore) : + KeyedObservableDelegate(settingsStore), KeyValueStore { + + override fun contains(key: String) = settingsStore.contains(key) + + override fun getDefaultValue(key: String, valueType: Class) = + DEFAULT_VALUE.toBoolean() as T + + override fun getValue(key: String, valueType: Class) = + (settingsStore.getInt(key) ?: DEFAULT_VALUE).toBoolean() as T + + override fun setValue(key: String, valueType: Class, value: T?) = + settingsStore.setInt(key, (value as? Boolean)?.toBrightnessMode()) + + /** Converts brightness mode integer to boolean. */ + private fun Int.toBoolean() = this == SCREEN_BRIGHTNESS_MODE_AUTOMATIC + + /** Converts boolean value to brightness mode integer. */ + private fun Boolean.toBrightnessMode() = + if (this) SCREEN_BRIGHTNESS_MODE_AUTOMATIC else SCREEN_BRIGHTNESS_MODE_MANUAL + } companion object { const val KEY = Settings.System.SCREEN_BRIGHTNESS_MODE + private const val DEFAULT_VALUE = SCREEN_BRIGHTNESS_MODE_MANUAL } } diff --git a/tests/robotests/src/com/android/settings/display/AutoBrightnessScreenTest.kt b/tests/robotests/src/com/android/settings/display/AutoBrightnessScreenTest.kt index c7f78cd82ec..6dd9708b478 100644 --- a/tests/robotests/src/com/android/settings/display/AutoBrightnessScreenTest.kt +++ b/tests/robotests/src/com/android/settings/display/AutoBrightnessScreenTest.kt @@ -28,6 +28,7 @@ import com.android.settingslib.PrimarySwitchPreference import com.android.settingslib.widget.SettingsThemeHelper.isExpressiveTheme import com.android.settingslib.widget.theme.R import com.google.common.truth.Truth.assertThat +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.Config @@ -35,6 +36,7 @@ import org.robolectric.annotation.Config // LINT.IfChange @RunWith(AndroidJUnit4::class) @Config(shadows = [SettingsShadowResources::class]) +@Ignore("robolectric runtime") class AutoBrightnessScreenTest { private val context: Context = ApplicationProvider.getApplicationContext()