Loading src/com/android/settings/display/DisplayWhiteBalancePreferenceController.java +77 −7 Original line number Diff line number Diff line Loading @@ -13,17 +13,34 @@ */ package com.android.settings.display; import android.app.ActivityManager; import android.content.ContentResolver; 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.os.UserHandle; import android.provider.Settings.Secure; import android.provider.Settings.System; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settings.core.TogglePreferenceController; public class DisplayWhiteBalancePreferenceController extends TogglePreferenceController { public class DisplayWhiteBalancePreferenceController extends TogglePreferenceController implements LifecycleObserver, OnStart, OnStop { private ColorDisplayManager mColorDisplayManager; @VisibleForTesting ContentObserver mContentObserver; private Preference mPreference; public DisplayWhiteBalancePreferenceController(Context context, String key) { super(context, key); Loading @@ -31,11 +48,7 @@ public class DisplayWhiteBalancePreferenceController extends TogglePreferenceCon @Override public int getAvailabilityStatus() { // Display white balance is only valid in linear light space. COLOR_MODE_SATURATED implies // unmanaged color mode, and hence unknown color processing conditions. return ColorDisplayManager.isDisplayWhiteBalanceAvailable(mContext) && getColorDisplayManager().getColorMode() != ColorDisplayManager.COLOR_MODE_SATURATED ? return getColorDisplayManager().isDisplayWhiteBalanceAvailable(mContext) ? AVAILABLE : DISABLED_FOR_USER; } Loading @@ -49,6 +62,50 @@ public class DisplayWhiteBalancePreferenceController extends TogglePreferenceCon return getColorDisplayManager().setDisplayWhiteBalanceEnabled(isChecked); } @Override public void onStart() { if (!isAvailable()) { return; } final ContentResolver cr = mContext.getContentResolver(); mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); updateVisibility(); } }; cr.registerContentObserver( Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED), false /* notifyForDescendants */, mContentObserver, ActivityManager.getCurrentUser()); cr.registerContentObserver( Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED), false /* notifyForDescendants */, mContentObserver, ActivityManager.getCurrentUser()); cr.registerContentObserver( System.getUriFor(System.DISPLAY_COLOR_MODE), false /* notifyForDescendants */, mContentObserver, ActivityManager.getCurrentUser()); updateVisibility(); } @Override public void onStop() { if (mContentObserver != null) { mContext.getContentResolver().unregisterContentObserver(mContentObserver); mContentObserver = null; } } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mPreference = screen.findPreference(getPreferenceKey()); } @VisibleForTesting ColorDisplayManager getColorDisplayManager() { if (mColorDisplayManager == null) { Loading @@ -56,4 +113,17 @@ public class DisplayWhiteBalancePreferenceController extends TogglePreferenceCon } return mColorDisplayManager; } @VisibleForTesting void updateVisibility() { if (mPreference != null) { ColorDisplayManager cdm = getColorDisplayManager(); // Display white balance is only valid in linear light space. COLOR_MODE_SATURATED // implies unmanaged color mode, and hence unknown color processing conditions. // We also disallow display white balance when color accessibility features are enabled. mPreference.setVisible(cdm.getColorMode() != ColorDisplayManager.COLOR_MODE_SATURATED && !cdm.areAccessibilityTransformsEnabled(mContext)); } } } tests/robotests/src/com/android/settings/display/DisplayWhiteBalancePreferenceControllerTest.java +126 −18 Original line number Diff line number Diff line package com.android.settings.display; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static com.google.common.truth.Truth.assertThat; import android.content.ContentResolver; import android.content.Context; import android.hardware.display.ColorDisplayManager; import android.provider.Settings; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.testutils.shadow.SettingsShadowResources; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; Loading @@ -27,6 +38,15 @@ public class DisplayWhiteBalancePreferenceControllerTest { @Mock private ColorDisplayManager mColorDisplayManager; private ContentResolver mContentResolver; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private PreferenceScreen mScreen; @Mock private Preference mPreference; private final String PREFERENCE_KEY = "display_white_balance"; @After public void tearDown() { Loading @@ -36,17 +56,21 @@ public class DisplayWhiteBalancePreferenceControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); mController = spy(new DisplayWhiteBalancePreferenceController(RuntimeEnvironment.application, "display_white_balance")); mContentResolver = RuntimeEnvironment.application.getContentResolver(); when(mContext.getContentResolver()).thenReturn(mContentResolver); when(mContext.getResources()).thenReturn(RuntimeEnvironment.application.getResources()); when(mScreen.findPreference(PREFERENCE_KEY)).thenReturn(mPreference); mController = spy(new DisplayWhiteBalancePreferenceController(mContext, PREFERENCE_KEY)); doReturn(mColorDisplayManager).when(mController).getColorDisplayManager(); } @Test public void isAvailable_configuredAvailable() { public void isAvailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); when(mColorDisplayManager.getColorMode()) .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); assertThat(mController.isAvailable()).isTrue(); } Loading @@ -54,20 +78,7 @@ public class DisplayWhiteBalancePreferenceControllerTest { public void isAvailable_configuredUnavailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false); when(mColorDisplayManager.getColorMode()) .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED); assertThat(mController.isAvailable()).isFalse(); SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false); when(mColorDisplayManager.getColorMode()) .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); assertThat(mController.isAvailable()).isFalse(); SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); when(mColorDisplayManager.getColorMode()) .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED); assertThat(mController.isAvailable()).isFalse(); } Loading @@ -94,4 +105,101 @@ public class DisplayWhiteBalancePreferenceControllerTest { when(mColorDisplayManager.isDisplayWhiteBalanceEnabled()).thenReturn(false); assertThat(mController.isChecked()).isFalse(); } @Test public void onStart_configuredUnavailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false); mController.displayPreference(mScreen); mController.onStart(); assertThat(mController.mContentObserver).isNull(); } @Test public void onStart_configuredAvailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); when(mColorDisplayManager.getColorMode()) .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); toggleAccessibilityInversion(false); toggleAccessibilityDaltonizer(false); mController.displayPreference(mScreen); mController.onStart(); assertThat(mController.mContentObserver).isNotNull(); } @Test public void visibility_configuredAvailableAccessibilityToggled() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); mController.displayPreference(mScreen); // Accessibility features disabled toggleAccessibilityInversion(false); reset(mPreference); mController.updateVisibility(); verify(mPreference).setVisible(true); toggleAccessibilityDaltonizer(false); reset(mPreference); mController.updateVisibility(); verify(mPreference).setVisible(true); // Accessibility features enabled one by one toggleAccessibilityInversion(true); mController.updateVisibility(); verify(mPreference).setVisible(false); toggleAccessibilityDaltonizer(true); reset(mPreference); mController.updateVisibility(); verify(mPreference).setVisible(false); // Accessibility features disabled one by one toggleAccessibilityInversion(false); reset(mPreference); mController.updateVisibility(); // Daltonizer is still enabled, so we expect the preference to still be invisible verify(mPreference).setVisible(false); // Now both a11y features are disabled, so we expect the preference to become visible toggleAccessibilityDaltonizer(false); mController.updateVisibility(); verify(mPreference).setVisible(true); } @Test public void visibility_configuredAvailableColorModeChanged() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); mController.displayPreference(mScreen); // Non-Saturated color mode selected when(mColorDisplayManager.getColorMode()).thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); reset(mPreference); mController.updateVisibility(); verify(mPreference).setVisible(true); // Saturated color mode selected when(mColorDisplayManager.getColorMode()).thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED); mController.updateVisibility(); verify(mPreference).setVisible(false); // Switch back to non-Saturated color mode when(mColorDisplayManager.getColorMode()).thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); reset(mPreference); mController.updateVisibility(); verify(mPreference).setVisible(true); } private void toggleAccessibilityInversion(boolean enable) { Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, enable ? 1 : 0); } private void toggleAccessibilityDaltonizer(boolean enable) { Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, enable ? 1 : 0); } } Loading
src/com/android/settings/display/DisplayWhiteBalancePreferenceController.java +77 −7 Original line number Diff line number Diff line Loading @@ -13,17 +13,34 @@ */ package com.android.settings.display; import android.app.ActivityManager; import android.content.ContentResolver; 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.os.UserHandle; import android.provider.Settings.Secure; import android.provider.Settings.System; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settings.core.TogglePreferenceController; public class DisplayWhiteBalancePreferenceController extends TogglePreferenceController { public class DisplayWhiteBalancePreferenceController extends TogglePreferenceController implements LifecycleObserver, OnStart, OnStop { private ColorDisplayManager mColorDisplayManager; @VisibleForTesting ContentObserver mContentObserver; private Preference mPreference; public DisplayWhiteBalancePreferenceController(Context context, String key) { super(context, key); Loading @@ -31,11 +48,7 @@ public class DisplayWhiteBalancePreferenceController extends TogglePreferenceCon @Override public int getAvailabilityStatus() { // Display white balance is only valid in linear light space. COLOR_MODE_SATURATED implies // unmanaged color mode, and hence unknown color processing conditions. return ColorDisplayManager.isDisplayWhiteBalanceAvailable(mContext) && getColorDisplayManager().getColorMode() != ColorDisplayManager.COLOR_MODE_SATURATED ? return getColorDisplayManager().isDisplayWhiteBalanceAvailable(mContext) ? AVAILABLE : DISABLED_FOR_USER; } Loading @@ -49,6 +62,50 @@ public class DisplayWhiteBalancePreferenceController extends TogglePreferenceCon return getColorDisplayManager().setDisplayWhiteBalanceEnabled(isChecked); } @Override public void onStart() { if (!isAvailable()) { return; } final ContentResolver cr = mContext.getContentResolver(); mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); updateVisibility(); } }; cr.registerContentObserver( Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED), false /* notifyForDescendants */, mContentObserver, ActivityManager.getCurrentUser()); cr.registerContentObserver( Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED), false /* notifyForDescendants */, mContentObserver, ActivityManager.getCurrentUser()); cr.registerContentObserver( System.getUriFor(System.DISPLAY_COLOR_MODE), false /* notifyForDescendants */, mContentObserver, ActivityManager.getCurrentUser()); updateVisibility(); } @Override public void onStop() { if (mContentObserver != null) { mContext.getContentResolver().unregisterContentObserver(mContentObserver); mContentObserver = null; } } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mPreference = screen.findPreference(getPreferenceKey()); } @VisibleForTesting ColorDisplayManager getColorDisplayManager() { if (mColorDisplayManager == null) { Loading @@ -56,4 +113,17 @@ public class DisplayWhiteBalancePreferenceController extends TogglePreferenceCon } return mColorDisplayManager; } @VisibleForTesting void updateVisibility() { if (mPreference != null) { ColorDisplayManager cdm = getColorDisplayManager(); // Display white balance is only valid in linear light space. COLOR_MODE_SATURATED // implies unmanaged color mode, and hence unknown color processing conditions. // We also disallow display white balance when color accessibility features are enabled. mPreference.setVisible(cdm.getColorMode() != ColorDisplayManager.COLOR_MODE_SATURATED && !cdm.areAccessibilityTransformsEnabled(mContext)); } } }
tests/robotests/src/com/android/settings/display/DisplayWhiteBalancePreferenceControllerTest.java +126 −18 Original line number Diff line number Diff line package com.android.settings.display; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static com.google.common.truth.Truth.assertThat; import android.content.ContentResolver; import android.content.Context; import android.hardware.display.ColorDisplayManager; import android.provider.Settings; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.testutils.shadow.SettingsShadowResources; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; Loading @@ -27,6 +38,15 @@ public class DisplayWhiteBalancePreferenceControllerTest { @Mock private ColorDisplayManager mColorDisplayManager; private ContentResolver mContentResolver; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private PreferenceScreen mScreen; @Mock private Preference mPreference; private final String PREFERENCE_KEY = "display_white_balance"; @After public void tearDown() { Loading @@ -36,17 +56,21 @@ public class DisplayWhiteBalancePreferenceControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); mController = spy(new DisplayWhiteBalancePreferenceController(RuntimeEnvironment.application, "display_white_balance")); mContentResolver = RuntimeEnvironment.application.getContentResolver(); when(mContext.getContentResolver()).thenReturn(mContentResolver); when(mContext.getResources()).thenReturn(RuntimeEnvironment.application.getResources()); when(mScreen.findPreference(PREFERENCE_KEY)).thenReturn(mPreference); mController = spy(new DisplayWhiteBalancePreferenceController(mContext, PREFERENCE_KEY)); doReturn(mColorDisplayManager).when(mController).getColorDisplayManager(); } @Test public void isAvailable_configuredAvailable() { public void isAvailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); when(mColorDisplayManager.getColorMode()) .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); assertThat(mController.isAvailable()).isTrue(); } Loading @@ -54,20 +78,7 @@ public class DisplayWhiteBalancePreferenceControllerTest { public void isAvailable_configuredUnavailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false); when(mColorDisplayManager.getColorMode()) .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED); assertThat(mController.isAvailable()).isFalse(); SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false); when(mColorDisplayManager.getColorMode()) .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); assertThat(mController.isAvailable()).isFalse(); SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); when(mColorDisplayManager.getColorMode()) .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED); assertThat(mController.isAvailable()).isFalse(); } Loading @@ -94,4 +105,101 @@ public class DisplayWhiteBalancePreferenceControllerTest { when(mColorDisplayManager.isDisplayWhiteBalanceEnabled()).thenReturn(false); assertThat(mController.isChecked()).isFalse(); } @Test public void onStart_configuredUnavailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false); mController.displayPreference(mScreen); mController.onStart(); assertThat(mController.mContentObserver).isNull(); } @Test public void onStart_configuredAvailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); when(mColorDisplayManager.getColorMode()) .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); toggleAccessibilityInversion(false); toggleAccessibilityDaltonizer(false); mController.displayPreference(mScreen); mController.onStart(); assertThat(mController.mContentObserver).isNotNull(); } @Test public void visibility_configuredAvailableAccessibilityToggled() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); mController.displayPreference(mScreen); // Accessibility features disabled toggleAccessibilityInversion(false); reset(mPreference); mController.updateVisibility(); verify(mPreference).setVisible(true); toggleAccessibilityDaltonizer(false); reset(mPreference); mController.updateVisibility(); verify(mPreference).setVisible(true); // Accessibility features enabled one by one toggleAccessibilityInversion(true); mController.updateVisibility(); verify(mPreference).setVisible(false); toggleAccessibilityDaltonizer(true); reset(mPreference); mController.updateVisibility(); verify(mPreference).setVisible(false); // Accessibility features disabled one by one toggleAccessibilityInversion(false); reset(mPreference); mController.updateVisibility(); // Daltonizer is still enabled, so we expect the preference to still be invisible verify(mPreference).setVisible(false); // Now both a11y features are disabled, so we expect the preference to become visible toggleAccessibilityDaltonizer(false); mController.updateVisibility(); verify(mPreference).setVisible(true); } @Test public void visibility_configuredAvailableColorModeChanged() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); mController.displayPreference(mScreen); // Non-Saturated color mode selected when(mColorDisplayManager.getColorMode()).thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); reset(mPreference); mController.updateVisibility(); verify(mPreference).setVisible(true); // Saturated color mode selected when(mColorDisplayManager.getColorMode()).thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED); mController.updateVisibility(); verify(mPreference).setVisible(false); // Switch back to non-Saturated color mode when(mColorDisplayManager.getColorMode()).thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); reset(mPreference); mController.updateVisibility(); verify(mPreference).setVisible(true); } private void toggleAccessibilityInversion(boolean enable) { Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, enable ? 1 : 0); } private void toggleAccessibilityDaltonizer(boolean enable) { Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, enable ? 1 : 0); } }