diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 11bf4c1eabc..9a8aa75976e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2508,6 +2508,22 @@ android:value="true" /> + + + + + + + + + + + + + + diff --git a/res/drawable-night/ic_contrast_medium.xml b/res/drawable-night/ic_contrast_medium.xml new file mode 100644 index 00000000000..dc8ddaeebb7 --- /dev/null +++ b/res/drawable-night/ic_contrast_medium.xml @@ -0,0 +1,28 @@ + + + + + diff --git a/res/drawable-night/ic_contrast_standard.xml b/res/drawable-night/ic_contrast_standard.xml new file mode 100644 index 00000000000..cdf61cf33d8 --- /dev/null +++ b/res/drawable-night/ic_contrast_standard.xml @@ -0,0 +1,28 @@ + + + + + diff --git a/res/drawable/accessibility_contrast_button_background.xml b/res/drawable/accessibility_contrast_button_background.xml new file mode 100644 index 00000000000..281fcef246a --- /dev/null +++ b/res/drawable/accessibility_contrast_button_background.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/color_contrast_preview_background.xml b/res/drawable/color_contrast_preview_background.xml new file mode 100644 index 00000000000..51d0ade2d73 --- /dev/null +++ b/res/drawable/color_contrast_preview_background.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/color_contrast_preview_bottom_appbar_background.xml b/res/drawable/color_contrast_preview_bottom_appbar_background.xml new file mode 100644 index 00000000000..f3392fb01b5 --- /dev/null +++ b/res/drawable/color_contrast_preview_bottom_appbar_background.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/color_contrast_preview_button_background.xml b/res/drawable/color_contrast_preview_button_background.xml new file mode 100644 index 00000000000..8b920874350 --- /dev/null +++ b/res/drawable/color_contrast_preview_button_background.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/res/drawable/color_contrast_preview_dialog_background.xml b/res/drawable/color_contrast_preview_dialog_background.xml new file mode 100644 index 00000000000..f60a271ec3d --- /dev/null +++ b/res/drawable/color_contrast_preview_dialog_background.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/color_contrast_preview_icon_edit_background.xml b/res/drawable/color_contrast_preview_icon_edit_background.xml new file mode 100644 index 00000000000..14c5f3c9340 --- /dev/null +++ b/res/drawable/color_contrast_preview_icon_edit_background.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/color_contrast_preview_icon_group_background.xml b/res/drawable/color_contrast_preview_icon_group_background.xml new file mode 100644 index 00000000000..b8554c19229 --- /dev/null +++ b/res/drawable/color_contrast_preview_icon_group_background.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/color_contrast_preview_icon_inbox_background.xml b/res/drawable/color_contrast_preview_icon_inbox_background.xml new file mode 100644 index 00000000000..45d82852456 --- /dev/null +++ b/res/drawable/color_contrast_preview_icon_inbox_background.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/res/drawable/color_contrast_preview_icon_star_background.xml b/res/drawable/color_contrast_preview_icon_star_background.xml new file mode 100644 index 00000000000..335ee886f7f --- /dev/null +++ b/res/drawable/color_contrast_preview_icon_star_background.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/color_contrast_preview_tag_background.xml b/res/drawable/color_contrast_preview_tag_background.xml new file mode 100644 index 00000000000..a7b051aa280 --- /dev/null +++ b/res/drawable/color_contrast_preview_tag_background.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/ic_article_24dp.xml b/res/drawable/ic_article_24dp.xml new file mode 100644 index 00000000000..0b38daaf643 --- /dev/null +++ b/res/drawable/ic_article_24dp.xml @@ -0,0 +1,27 @@ + + + + diff --git a/res/drawable/ic_article_filled_24dp.xml b/res/drawable/ic_article_filled_24dp.xml new file mode 100644 index 00000000000..e22d151beb7 --- /dev/null +++ b/res/drawable/ic_article_filled_24dp.xml @@ -0,0 +1,26 @@ + + + + diff --git a/res/drawable/ic_chat_bubble_24dp.xml b/res/drawable/ic_chat_bubble_24dp.xml new file mode 100644 index 00000000000..c7ad6bf28a1 --- /dev/null +++ b/res/drawable/ic_chat_bubble_24dp.xml @@ -0,0 +1,26 @@ + + + + diff --git a/res/drawable/ic_color_contrast.xml b/res/drawable/ic_color_contrast.xml new file mode 100644 index 00000000000..9d56ada2f0c --- /dev/null +++ b/res/drawable/ic_color_contrast.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/ic_contrast_high.xml b/res/drawable/ic_contrast_high.xml new file mode 100644 index 00000000000..363f2a85ce5 --- /dev/null +++ b/res/drawable/ic_contrast_high.xml @@ -0,0 +1,28 @@ + + + + + diff --git a/res/drawable/ic_contrast_medium.xml b/res/drawable/ic_contrast_medium.xml new file mode 100644 index 00000000000..04e48d013ab --- /dev/null +++ b/res/drawable/ic_contrast_medium.xml @@ -0,0 +1,28 @@ + + + + + diff --git a/res/drawable/ic_contrast_standard.xml b/res/drawable/ic_contrast_standard.xml new file mode 100644 index 00000000000..9f0c5af62de --- /dev/null +++ b/res/drawable/ic_contrast_standard.xml @@ -0,0 +1,28 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/ic_edit_24dp.xml b/res/drawable/ic_edit_24dp.xml new file mode 100644 index 00000000000..c9dbfc33343 --- /dev/null +++ b/res/drawable/ic_edit_24dp.xml @@ -0,0 +1,26 @@ + + + + diff --git a/res/drawable/ic_group_24dp.xml b/res/drawable/ic_group_24dp.xml new file mode 100644 index 00000000000..92815c2cc2f --- /dev/null +++ b/res/drawable/ic_group_24dp.xml @@ -0,0 +1,26 @@ + + + + diff --git a/res/drawable/ic_inbox_24dp.xml b/res/drawable/ic_inbox_24dp.xml new file mode 100644 index 00000000000..7800ea145ef --- /dev/null +++ b/res/drawable/ic_inbox_24dp.xml @@ -0,0 +1,26 @@ + + + + diff --git a/res/drawable/ic_star_24dp.xml b/res/drawable/ic_star_24dp.xml new file mode 100644 index 00000000000..38535e6c5fd --- /dev/null +++ b/res/drawable/ic_star_24dp.xml @@ -0,0 +1,26 @@ + + + + diff --git a/res/layout/accessibility_color_contrast_preview.xml b/res/layout/accessibility_color_contrast_preview.xml new file mode 100644 index 00000000000..2646709dbf4 --- /dev/null +++ b/res/layout/accessibility_color_contrast_preview.xml @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/accessibility_color_contrast_selector.xml b/res/layout/accessibility_color_contrast_selector.xml new file mode 100644 index 00000000000..f7ba28b5b32 --- /dev/null +++ b/res/layout/accessibility_color_contrast_selector.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 4b96486be7b..bdf329c03d4 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -477,4 +477,13 @@ 80dp 24dp + + + 90dp + 82dp + 20dp + 2dp + 14sp + 4dp + 16dp diff --git a/res/values/strings.xml b/res/values/strings.xml index 0f87d87e4af..0384319126a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4624,6 +4624,28 @@ Display Color and motion + + Color contrast + + Higher contrast makes text, buttons, and icons stand out more. Choose the contrast that looks best to you. + + Some apps may not support all color and text contrast settings + + Adjust how colors and text look against your screen\'s background color + + Preview + + Helen, Adam + + 2 days ago + + Follow up? + + Business trip report + + For further assistance, please reach out to \nmyself or Helen. This report will be + + Client Expenses Turn screen darker @@ -4925,6 +4947,10 @@ High contrast text Change text color to black or white. Maximizes contrast with the background. + + Maximize text contrast + + Change text color to black or white to increase contrast with the background. Auto update screen magnification @@ -12886,6 +12912,8 @@ Contrast Standard + + Default Medium diff --git a/res/xml/accessibility_color_and_motion.xml b/res/xml/accessibility_color_and_motion.xml index a500b72d958..35222347a29 100644 --- a/res/xml/accessibility_color_and_motion.xml +++ b/res/xml/accessibility_color_and_motion.xml @@ -21,6 +21,16 @@ android:persistent="false" android:title="@string/accessibility_color_and_motion_title"> + + + + + + + + + + + + + + + diff --git a/res/xml/accessibility_text_reading_options.xml b/res/xml/accessibility_text_reading_options.xml index 0711a3fa737..795c4ffb9fc 100644 --- a/res/xml/accessibility_text_reading_options.xml +++ b/res/xml/accessibility_text_reading_options.xml @@ -57,9 +57,7 @@ android:key="toggle_high_text_contrast_preference" android:persistent="false" android:summary="@string/accessibility_toggle_high_text_contrast_preference_summary" - android:title="@string/accessibility_toggle_high_text_contrast_preference_title" - settings:controller= - "com.android.settings.accessibility.HighTextContrastPreferenceController" /> + android:title="@string/accessibility_toggle_high_text_contrast_preference_title" /> mContrastButtons = new HashMap<>(); + + public ContrastSelectorPreferenceController(@NonNull Context context, + @NonNull String preferenceKey) { + super(context, preferenceKey); + + mMainExecutor = mContext.getMainExecutor(); + mUiModeManager = mContext.getSystemService(UiModeManager.class); + } + + @Override + public void displayPreference(@NonNull PreferenceScreen screen) { + super.displayPreference(screen); + + final LayoutPreference mLayoutPreference = + screen.findPreference(KEY_COLOR_CONTRAST_SELECTOR); + + mContrastButtons = Map.ofEntries( + Map.entry(CONTRAST_LEVEL_STANDARD, + mLayoutPreference.findViewById(R.id.contrast_button_default)), + Map.entry(CONTRAST_LEVEL_MEDIUM, + mLayoutPreference.findViewById(R.id.contrast_button_medium)), + Map.entry(CONTRAST_LEVEL_HIGH, + mLayoutPreference.findViewById(R.id.contrast_button_high)) + ); + + mContrastButtons.forEach((contrastLevel, contrastButton) -> { + contrastButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(@Nullable View v) { + Settings.Secure.putFloat(mContext.getContentResolver(), + Settings.Secure.CONTRAST_LEVEL, + fromContrastLevel(contrastLevel)); + } + }); + }); + + highlightContrast(toContrastLevel(mUiModeManager.getContrast())); + } + + @Override + public int getAvailabilityStatus() { + // The main preferences screen is feature guarded, so this always returns AVAILABLE. + return AVAILABLE; + } + + @Override + public void onStart() { + mUiModeManager.addContrastChangeListener(mMainExecutor, this); + } + + @Override + public void onStop() { + mUiModeManager.removeContrastChangeListener(this); + } + + @Override + public void onContrastChanged(float contrast) { + highlightContrast(toContrastLevel(contrast)); + } + + private void highlightContrast(int contrast) { + mContrastButtons.forEach((level, button) -> { + button.setSelected(level == contrast); + }); + } +} diff --git a/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java b/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java index a90af2182f7..5976ef51317 100644 --- a/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java +++ b/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java @@ -117,6 +117,11 @@ public class TextReadingPreferenceFragment extends DashboardFragment { } } } + + if (Flags.enableColorContrastControl()) { + // High text contrast toggle will be added inside Color Contrast page on V+. + removePreference(HIGH_TEXT_CONTRAST_KEY); + } } @Override @@ -203,10 +208,12 @@ public class TextReadingPreferenceFragment extends DashboardFragment { mFontWeightAdjustmentController.setEntryPoint(mEntryPoint); controllers.add(mFontWeightAdjustmentController); - final HighTextContrastPreferenceController highTextContrastController = - new HighTextContrastPreferenceController(context, HIGH_TEXT_CONTRAST_KEY); - highTextContrastController.setEntryPoint(mEntryPoint); - controllers.add(highTextContrastController); + if (!Flags.enableColorContrastControl()) { + final HighTextContrastPreferenceController highTextContrastController = + new HighTextContrastPreferenceController(context, HIGH_TEXT_CONTRAST_KEY); + highTextContrastController.setEntryPoint(mEntryPoint); + controllers.add(highTextContrastController); + } final TextReadingResetController resetController = new TextReadingResetController(context, RESET_KEY, diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 86582c7c5bb..e08e8560c3c 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -29,6 +29,7 @@ import com.android.settings.accessibility.AccessibilitySettings; import com.android.settings.accessibility.AccessibilitySettingsForSetupWizard; import com.android.settings.accessibility.CaptioningPropertiesFragment; import com.android.settings.accessibility.ColorAndMotionFragment; +import com.android.settings.accessibility.ColorContrastFragment; import com.android.settings.accessibility.TextReadingPreferenceFragment; import com.android.settings.accessibility.TextReadingPreferenceFragmentForSetupWizard; import com.android.settings.accessibility.ToggleColorInversionPreferenceFragment; @@ -379,6 +380,7 @@ public class SettingsGateway { TurnScreenOnDetails.class.getName(), NfcAndPaymentFragment.class.getName(), ColorAndMotionFragment.class.getName(), + ColorContrastFragment.class.getName(), LongBackgroundTasksDetails.class.getName(), RegionalPreferencesEntriesFragment.class.getName(), BatteryInfoFragment.class.getName(), diff --git a/tests/robotests/src/com/android/settings/accessibility/ColorContrastFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ColorContrastFragmentTest.java new file mode 100644 index 00000000000..f90374508e1 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/ColorContrastFragmentTest.java @@ -0,0 +1,86 @@ +/* + * 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.accessibility; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.UiModeManager; +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.R; +import com.android.settings.testutils.XmlTestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import java.util.List; + +/** Tests for {@link ColorContrastFragment}. */ +@RunWith(RobolectricTestRunner.class) +public class ColorContrastFragmentTest { + + private ColorContrastFragment mFragment; + private Context mContext; + @Mock + private UiModeManager mUiService; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mFragment = spy(new ColorContrastFragment()); + mContext = spy(ApplicationProvider.getApplicationContext()); + when(mFragment.getContext()).thenReturn(mContext); + when(mContext.getSystemService(UiModeManager.class)).thenReturn(mUiService); + } + + @Test + public void getMetricsCategory_returnsCorrectCategory() { + assertThat(mFragment.getMetricsCategory()).isEqualTo(0); + } + + @Test + public void getPreferenceScreenResId_returnsCorrectXml() { + assertThat(mFragment.getPreferenceScreenResId()).isEqualTo( + R.xml.accessibility_color_contrast); + } + + @Test + public void getLogTag_returnsCorrectTag() { + assertThat(mFragment.getLogTag()).isEqualTo("ColorContrastFragment"); + } + + @Test + public void getNonIndexableKeys_existInXmlLayout() { + final List niks = + ShortcutsSettingsFragment.SEARCH_INDEX_DATA_PROVIDER + .getNonIndexableKeys(mContext); + final List keys = + XmlTestUtils.getKeysFromPreferenceXml(mContext, + R.xml.accessibility_color_contrast); + assertThat(keys).containsAtLeastElementsIn(niks); + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/ContrastPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ContrastPreferenceControllerTest.java new file mode 100644 index 00000000000..219f3d971b1 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/ContrastPreferenceControllerTest.java @@ -0,0 +1,70 @@ +/* + * 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.accessibility; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.flag.junit.SetFlagsRule; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.core.BasePreferenceController; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +/** Tests for {@link ContrastPreferenceController}. */ +@RunWith(RobolectricTestRunner.class) +public class ContrastPreferenceControllerTest { + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private static final String PREFERENCE_KEY = "preference_key"; + + private Context mContext; + private ContrastPreferenceController mController; + + @Before + public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); + mController = new ContrastPreferenceController(mContext, PREFERENCE_KEY); + } + + @Test + public void getAvailabilityStatus_flagsEnabled_shouldReturnAvailable() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_COLOR_CONTRAST_CONTROL); + + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_flagsDisabled_shouldReturnUnsupported() { + mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_COLOR_CONTRAST_CONTROL); + + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE); + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/ContrastSelectorPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ContrastSelectorPreferenceControllerTest.java new file mode 100644 index 00000000000..38d6e801538 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/ContrastSelectorPreferenceControllerTest.java @@ -0,0 +1,115 @@ +/* + * 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.accessibility; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.UiModeManager; +import android.content.Context; +import android.widget.FrameLayout; + +import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.widget.LayoutPreference; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import java.util.concurrent.Executor; + +/** Tests for {@link ContrastSelectorPreferenceController}. */ +@RunWith(RobolectricTestRunner.class) +public class ContrastSelectorPreferenceControllerTest { + + private static final String PREFERENCE_KEY = "color_contrast_selector"; + + @Mock + private UiModeManager mUiService; + @Mock + private Executor mExecutor; + @Mock + private PreferenceScreen mScreen; + @Mock + private FrameLayout mFrameLayout; + @Mock + private LayoutPreference mLayoutPreference; + private Context mContext; + private ContrastSelectorPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(ApplicationProvider.getApplicationContext()); + when(mContext.getMainExecutor()).thenReturn(mExecutor); + when(mContext.getSystemService(UiModeManager.class)).thenReturn(mUiService); + mController = new ContrastSelectorPreferenceController(mContext, PREFERENCE_KEY); + when(mScreen.findPreference(PREFERENCE_KEY)).thenReturn(mLayoutPreference); + when(mLayoutPreference.findViewById(anyInt())).thenReturn(mFrameLayout); + } + + @Test + public void getAvailabilityStatus_byDefault_shouldReturnAvailable() { + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.AVAILABLE); + } + + @Test + public void onStart_shouldAddContrastListener() { + mController.displayPreference(mScreen); + mController.onStart(); + + verify(mUiService).addContrastChangeListener(mExecutor, mController); + } + + @Test + public void onStop_shouldRemoveContrastListener() { + mController.displayPreference(mScreen); + mController.onStart(); + mController.onStop(); + + verify(mUiService).removeContrastChangeListener(mController); + } + + @Test + public void displayPreference_shouldAddClickListener() { + mController.displayPreference(mScreen); + + verify(mFrameLayout, times(3)).setOnClickListener(any()); + } + + @Test + public void onContrastChanged_buttonShouldBeSelected() { + mController.displayPreference(mScreen); + mController.onContrastChanged(1); + + verify(mFrameLayout, times(2)).setSelected(true); + } +}