From cc96950d120b8259aa1ea03b7d552db3d79cac64 Mon Sep 17 00:00:00 2001 From: Vadym Omelnytskyi Date: Thu, 20 Feb 2025 01:49:48 +0000 Subject: [PATCH] Display: make Colors settings entry preference reactive Added `display_color_mode` listener to Colors preference. As a result, it becomes reactive and updates its color mode value summary. Flag: EXEMPT minor change Bug: 397659800 Test: changed color mode using `adb` commands and verify that Colors summary reacts and print correct color mode Change-Id: I963768e3dbb43b547ec53e6445b2791ec0f57cff --- .../ColorModePreferenceController.java | 45 +++++++++++++- .../ColorModePreferenceControllerTest.kt | 60 ++++++++++++++++++- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/display/ColorModePreferenceController.java b/src/com/android/settings/display/ColorModePreferenceController.java index 04cd2c0f434..2fa3452528b 100644 --- a/src/com/android/settings/display/ColorModePreferenceController.java +++ b/src/com/android/settings/display/ColorModePreferenceController.java @@ -14,15 +14,37 @@ package com.android.settings.display; import android.content.Context; +import android.database.ContentObserver; import android.hardware.display.ColorDisplayManager; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; import com.android.settings.core.BasePreferenceController; -public class ColorModePreferenceController extends BasePreferenceController { +public class ColorModePreferenceController extends BasePreferenceController + implements LifecycleObserver { + + private Preference mPreference; + + private final ContentObserver mContentObserver = new ContentObserver( + new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange, @Nullable Uri uri) { + if (mPreference != null) { + updateState(mPreference); + } + } + }; public ColorModePreferenceController(@NonNull Context context, @NonNull String key) { super(context, key); @@ -36,11 +58,32 @@ public class ColorModePreferenceController extends BasePreferenceController { AVAILABLE : DISABLED_FOR_USER; } + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + public void onResume() { + mContext.getContentResolver().registerContentObserver( + Settings.System.getUriFor(Settings.System.DISPLAY_COLOR_MODE), + /* notifyForDescendants= */ false, + mContentObserver); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) + public void onPause() { + mContext.getContentResolver().unregisterContentObserver(mContentObserver); + } + @Override public CharSequence getSummary() { return getColorModeName(); } + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + if (mPreference != null) { + updateState(mPreference); + } + } + @Override public void updateState(@Nullable Preference preference) { if (preference == null) { diff --git a/tests/robotests/src/com/android/settings/display/colors/ColorModePreferenceControllerTest.kt b/tests/robotests/src/com/android/settings/display/colors/ColorModePreferenceControllerTest.kt index eee87ac00e9..4371bae4910 100644 --- a/tests/robotests/src/com/android/settings/display/colors/ColorModePreferenceControllerTest.kt +++ b/tests/robotests/src/com/android/settings/display/colors/ColorModePreferenceControllerTest.kt @@ -15,10 +15,15 @@ */ package com.android.settings.display +import android.content.ContentResolver import android.content.Context +import android.database.ContentObserver import android.hardware.display.ColorDisplayManager +import android.provider.Settings import androidx.preference.Preference +import androidx.preference.PreferenceScreen +import androidx.preference.PreferenceManager import androidx.test.core.app.ApplicationProvider import com.android.settingslib.testutils.shadow.ShadowColorDisplayManager @@ -31,22 +36,34 @@ import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.robolectric.shadow.api.Shadow +import org.robolectric.shadows.ShadowContentResolver @RunWith(RobolectricTestRunner::class) -@Config(shadows = [ShadowColorDisplayManager::class]) +@Config(shadows = [ShadowColorDisplayManager::class, ShadowContentResolver::class]) class ColorModePreferenceControllerTest { private lateinit var context: Context private lateinit var preference: Preference private lateinit var controller: ColorModePreferenceController private lateinit var shadowColorDisplayManager: ShadowColorDisplayManager + private lateinit var shadowContentResolver: ShadowContentResolver @Before fun setup() { context = ApplicationProvider.getApplicationContext() + controller = ColorModePreferenceController(context, "test") preference = Preference(context) + val preferenceManager = PreferenceManager(context) + val preferenceScreen = preferenceManager.createPreferenceScreen(context) + preference.setKey(controller.getPreferenceKey()); + preferenceScreen.addPreference(preference) + shadowColorDisplayManager = Shadow.extract( - context.getSystemService(ColorDisplayManager::class.java)); + context.getSystemService(ColorDisplayManager::class.java)) + val contentResolver = context.getContentResolver(); + shadowContentResolver = Shadow.extract(contentResolver) + + controller.displayPreference(preferenceScreen) } @Test @@ -80,4 +97,43 @@ class ColorModePreferenceControllerTest { val naturalColorModeName = context.getString(R.string.color_mode_option_natural) assertThat(preference.summary.toString()).isEqualTo(naturalColorModeName) } + + @Test + fun onResume_verifyRegisterColorModeObserver() { + controller.onResume() + assertThat(shadowContentResolver.getContentObservers( + Settings.System.getUriFor(Settings.System.DISPLAY_COLOR_MODE))) + .hasSize(1) + } + + @Test + fun onPause_verifyUnregisterColorModeObserver() { + controller.onResume() + controller.onPause() + assertThat(shadowContentResolver.getContentObservers( + Settings.System.getUriFor(Settings.System.DISPLAY_COLOR_MODE))) + .isEmpty() + } + + @Test + fun contentObserver_onChange_updatesPreferenceSummary() { + controller.onResume() + assertThat(shadowContentResolver.getContentObservers( + Settings.System.getUriFor(Settings.System.DISPLAY_COLOR_MODE))) + .hasSize(1) + + shadowColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL) + triggerOnChangeListener() + assertThat(preference.summary).isEqualTo(context.getString(R.string.color_mode_option_natural)) + + shadowColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC) + triggerOnChangeListener() + assertThat(preference.summary).isEqualTo(context.getString(R.string.color_mode_option_automatic)) + } + + private fun triggerOnChangeListener() { + shadowContentResolver.getContentObservers( + Settings.System.getUriFor(Settings.System.DISPLAY_COLOR_MODE)) + .forEach {it.onChange(false, null)}; + } } \ No newline at end of file