From a1687df27be8f9b5a073760ce6697773c634b340 Mon Sep 17 00:00:00 2001 From: Daniel Solomon Date: Fri, 30 Mar 2018 18:11:38 -0700 Subject: [PATCH] Disable user control of color mode depending on Accessibility The Accessibility settings for color inversion and color correction are incompatible with some color modes. When either of these settings is enabled, disable GUI color mode controls. Bug: 68856024 Change-Id: I12fad22190283bac38592b94e88d865d3af978ad --- .../display/ColorModePreferenceFragment.java | 50 ++++++++++--- .../ColorModePreferenceFragmentTest.java | 73 ++++++++++++++++--- 2 files changed, 103 insertions(+), 20 deletions(-) diff --git a/src/com/android/settings/display/ColorModePreferenceFragment.java b/src/com/android/settings/display/ColorModePreferenceFragment.java index 5f5445b9483..6e4bd1f8e44 100644 --- a/src/com/android/settings/display/ColorModePreferenceFragment.java +++ b/src/com/android/settings/display/ColorModePreferenceFragment.java @@ -16,6 +16,7 @@ package com.android.settings.display; import android.content.Context; import android.graphics.drawable.Drawable; import android.support.annotation.VisibleForTesting; +import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import com.android.internal.app.ColorDisplayController; @@ -24,13 +25,15 @@ import com.android.internal.logging.nano.MetricsProto; import com.android.settings.applications.LayoutPreference; import com.android.settings.R; import com.android.settings.widget.RadioButtonPickerFragment; +import com.android.settings.widget.RadioButtonPreference; import com.android.settingslib.widget.CandidateInfo; import java.util.Arrays; import java.util.List; @SuppressWarnings("WeakerAccess") -public class ColorModePreferenceFragment extends RadioButtonPickerFragment { +public class ColorModePreferenceFragment extends RadioButtonPickerFragment + implements ColorDisplayController.Callback { @VisibleForTesting static final String KEY_COLOR_MODE_NATURAL = "color_mode_natural"; @@ -48,6 +51,16 @@ public class ColorModePreferenceFragment extends RadioButtonPickerFragment { public void onAttach(Context context) { super.onAttach(context); mController = new ColorDisplayController(context); + mController.setListener(this); + } + + @Override + public void onDetach() { + super.onDetach(); + if (mController != null) { + mController.setListener(null); + mController = null; + } } @Override @@ -71,15 +84,16 @@ public class ColorModePreferenceFragment extends RadioButtonPickerFragment { @Override protected List getCandidates() { Context c = getContext(); + final boolean enabled = !mController.getAccessibilityTransformActivated(); return Arrays.asList( - new ColorModeCandidateInfo(c.getString(R.string.color_mode_option_natural), - KEY_COLOR_MODE_NATURAL), - new ColorModeCandidateInfo(c.getString(R.string.color_mode_option_boosted), - KEY_COLOR_MODE_BOOSTED), - new ColorModeCandidateInfo(c.getString(R.string.color_mode_option_saturated), - KEY_COLOR_MODE_SATURATED), - new ColorModeCandidateInfo(c.getString(R.string.color_mode_option_automatic), - KEY_COLOR_MODE_AUTOMATIC) + new ColorModeCandidateInfo(c.getText(R.string.color_mode_option_natural), + KEY_COLOR_MODE_NATURAL, enabled), + new ColorModeCandidateInfo(c.getText(R.string.color_mode_option_boosted), + KEY_COLOR_MODE_BOOSTED, enabled), + new ColorModeCandidateInfo(c.getText(R.string.color_mode_option_saturated), + KEY_COLOR_MODE_SATURATED, enabled), + new ColorModeCandidateInfo(c.getText(R.string.color_mode_option_automatic), + KEY_COLOR_MODE_AUTOMATIC, enabled) ); } @@ -120,8 +134,8 @@ public class ColorModePreferenceFragment extends RadioButtonPickerFragment { private final CharSequence mLabel; private final String mKey; - ColorModeCandidateInfo(CharSequence label, String key) { - super(true); + ColorModeCandidateInfo(CharSequence label, String key, boolean enabled) { + super(enabled); mLabel = label; mKey = key; } @@ -142,4 +156,18 @@ public class ColorModePreferenceFragment extends RadioButtonPickerFragment { } } + @Override + public void onAccessibilityTransformChanged(boolean state) { + // Disable controls when a11y transforms are enabled, and vice versa + final PreferenceScreen screen = getPreferenceScreen(); + if (screen != null) { + final int count = screen.getPreferenceCount(); + for (int i = 0; i < count; i++) { + final Preference pref = screen.getPreference(i); + if (pref instanceof RadioButtonPreference) { + pref.setEnabled(!state); + } + } + } + } } diff --git a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java index e962441b4d4..6df0c0411c8 100644 --- a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java @@ -16,8 +16,10 @@ package com.android.settings.display; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Answers.RETURNS_DEEP_STUBS; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -32,6 +34,7 @@ import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; import com.android.settings.applications.LayoutPreference; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.widget.RadioButtonPreference; import com.android.settingslib.widget.CandidateInfo; import org.junit.Before; @@ -39,11 +42,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; +import java.util.ArrayList; import java.util.List; @RunWith(SettingsRobolectricTestRunner.class) @@ -54,11 +57,14 @@ public class ColorModePreferenceFragmentTest { @Mock private ColorDisplayController mController; + @Mock + private PreferenceScreen mScreen; + @Before public void setup() { MockitoAnnotations.initMocks(this); - mFragment = spy(new ColorModePreferenceFragment()); + mFragment = spy(new ColorModePreferenceFragmentTestable(mScreen)); ReflectionHelpers.setField(mFragment, "mController", mController); } @@ -86,7 +92,7 @@ public class ColorModePreferenceFragmentTest { @Test public void getKey_natural() { - Mockito.when(mController.getColorMode()) + when(mController.getColorMode()) .thenReturn(ColorDisplayController.COLOR_MODE_NATURAL); assertThat(mFragment.getDefaultKey()) @@ -95,7 +101,7 @@ public class ColorModePreferenceFragmentTest { @Test public void getKey_boosted() { - Mockito.when(mController.getColorMode()) + when(mController.getColorMode()) .thenReturn(ColorDisplayController.COLOR_MODE_BOOSTED); assertThat(mFragment.getDefaultKey()) @@ -104,7 +110,7 @@ public class ColorModePreferenceFragmentTest { @Test public void getKey_saturated() { - Mockito.when(mController.getColorMode()) + when(mController.getColorMode()) .thenReturn(ColorDisplayController.COLOR_MODE_SATURATED); assertThat(mFragment.getDefaultKey()) @@ -141,15 +147,64 @@ public class ColorModePreferenceFragmentTest { @Test public void addStaticPreferences_shouldAddPreviewImage() { - PreferenceScreen mockPreferenceScreen = Mockito.mock(PreferenceScreen.class); - LayoutPreference mockPreview = Mockito.mock(LayoutPreference.class); + PreferenceScreen mockPreferenceScreen = mock(PreferenceScreen.class); + LayoutPreference mockPreview = mock(LayoutPreference.class); ArgumentCaptor preferenceCaptor = ArgumentCaptor.forClass(Preference.class); mFragment.configureAndInstallPreview(mockPreview, mockPreferenceScreen); - Mockito.verify(mockPreview, times(1)).setSelectable(false); - Mockito.verify(mockPreferenceScreen, times(1)).addPreference(preferenceCaptor.capture()); + verify(mockPreview, times(1)).setSelectable(false); + verify(mockPreferenceScreen, times(1)).addPreference(preferenceCaptor.capture()); assertThat(preferenceCaptor.getValue()).isEqualTo(mockPreview); } + + @Test + public void onAccessibilityTransformChanged_toggles() { + final int radioPrefsCount = 3; + List radioPrefs = new ArrayList<>(); + for (int i = 0; i < radioPrefsCount; i++) { + radioPrefs.add(mock(RadioButtonPreference.class)); + } + + when(mScreen.getPreferenceCount()).thenReturn(radioPrefs.size()); + when(mScreen.getPreference(anyInt())).thenAnswer(invocation -> { + final Object[] args = invocation.getArguments(); + return radioPrefs.get((int) args[0]); + }); + + mFragment.onAccessibilityTransformChanged(true /* state */); + for (int i = 0; i < radioPrefsCount; i++) { + verify(radioPrefs.get(i)).setEnabled(false); + } + + mFragment.onAccessibilityTransformChanged(false /* state */); + for (int i = 0; i < radioPrefsCount; i++) { + verify(radioPrefs.get(i)).setEnabled(true); + } + } + + private static class ColorModePreferenceFragmentTestable + extends ColorModePreferenceFragment { + + private final PreferenceScreen mPreferenceScreen; + + private ColorModePreferenceFragmentTestable(PreferenceScreen screen) { + mPreferenceScreen = screen; + } + + /** + * A method to return a mock PreferenceScreen. + * A real ColorModePreferenceFragment calls super.getPreferenceScreen() to get its + * PreferenceScreen handle, which internally dereferenced a PreferenceManager. But in this + * test scenario, the PreferenceManager object is uninitialized, so we need to supply the + * PreferenceScreen directly. + * + * @return a mock PreferenceScreen + */ + @Override + public PreferenceScreen getPreferenceScreen() { + return mPreferenceScreen; + } + } }