diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 57c577d90e5..d7c1baa9581 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2471,6 +2471,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 5873b1abe8c..32a3e03d639 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4599,6 +4599,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 @@ -12828,6 +12850,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/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 63ce3310371..92e3efd5003 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -117,6 +117,8 @@ public class Settings extends SettingsActivity { public static class TextReadingSettingsActivity extends SettingsActivity { /* empty */ } /** Activity for text color and motion settings. */ public static class ColorAndMotionActivity extends SettingsActivity { /* empty */ } + /** Activity for color contrast settings. */ + public static class ColorContrastActivity extends SettingsActivity { /* empty */ } /** Activity for the security dashboard. */ public static class SecurityDashboardActivity extends SettingsActivity { diff --git a/src/com/android/settings/accessibility/ColorContrastFragment.java b/src/com/android/settings/accessibility/ColorContrastFragment.java new file mode 100644 index 00000000000..a5726579b38 --- /dev/null +++ b/src/com/android/settings/accessibility/ColorContrastFragment.java @@ -0,0 +1,49 @@ +/* + * 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 com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.search.SearchIndexable; + +/** Accessibility settings for color contrast. */ +@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) +public class ColorContrastFragment extends DashboardFragment { + + private static final String TAG = "ColorContrastFragment"; + + + @Override + protected int getPreferenceScreenResId() { + return R.xml.accessibility_color_contrast; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + public int getMetricsCategory() { + // TODO(b/326539398): Add metrics tracking for color contrast. + return 0; + } + + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.accessibility_color_contrast); +} diff --git a/src/com/android/settings/accessibility/ContrastPreferenceController.java b/src/com/android/settings/accessibility/ContrastPreferenceController.java new file mode 100644 index 00000000000..4e9a9ec77e5 --- /dev/null +++ b/src/com/android/settings/accessibility/ContrastPreferenceController.java @@ -0,0 +1,38 @@ +/* + * 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 android.content.Context; + +import androidx.annotation.NonNull; + +import com.android.settings.core.BasePreferenceController; + +/** + * Controller for {@link ColorContrastFragment}. + */ +public class ContrastPreferenceController extends BasePreferenceController { + + public ContrastPreferenceController(@NonNull Context context, @NonNull String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return Flags.enableColorContrastControl() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } +} diff --git a/src/com/android/settings/accessibility/ContrastSelectorPreferenceController.java b/src/com/android/settings/accessibility/ContrastSelectorPreferenceController.java new file mode 100644 index 00000000000..b99680fa0b6 --- /dev/null +++ b/src/com/android/settings/accessibility/ContrastSelectorPreferenceController.java @@ -0,0 +1,122 @@ +/* + * 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 android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_HIGH; +import static android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_MEDIUM; +import static android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_STANDARD; +import static android.app.UiModeManager.ContrastUtils.fromContrastLevel; +import static android.app.UiModeManager.ContrastUtils.toContrastLevel; + +import android.app.UiModeManager; +import android.content.Context; +import android.provider.Settings; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +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.settingslib.widget.LayoutPreference; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * Controller for contrast selector. + */ +public class ContrastSelectorPreferenceController extends BasePreferenceController + implements LifecycleObserver, OnStart, OnStop, UiModeManager.ContrastChangeListener { + + private static final String KEY_COLOR_CONTRAST_SELECTOR = "color_contrast_selector"; + + private final Executor mMainExecutor; + private final UiModeManager mUiModeManager; + private Map 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/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index e3131f7753f..1b6c231f966 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; @@ -381,6 +382,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); + } +}