diff --git a/res/drawable/accessibility_color_inversion_preview.png b/res/drawable/accessibility_color_inversion_preview.png new file mode 100644 index 00000000000..5c9f3ea10a1 Binary files /dev/null and b/res/drawable/accessibility_color_inversion_preview.png differ diff --git a/res/layout/color_inversion_preview.xml b/res/layout/color_inversion_preview.xml new file mode 100644 index 00000000000..18a0bb8537d --- /dev/null +++ b/res/layout/color_inversion_preview.xml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index cd473a296ba..cb3dae9ba23 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4903,8 +4903,10 @@ Touch & hold delay Color inversion + + Invert colors - May affect performance + Turn light screens dark so people who are sensitive to bright light can have a better viewing experience.\n\nNote: dark colors will turn light. Images will also be inverted. Dwell timing @@ -4919,7 +4921,7 @@ Ring vibration Touch feedback - + Use %1$s Use color correction diff --git a/res/xml/accessibility_color_inversion_settings.xml b/res/xml/accessibility_color_inversion_settings.xml new file mode 100644 index 00000000000..de1511fbc81 --- /dev/null +++ b/res/xml/accessibility_color_inversion_settings.xml @@ -0,0 +1,42 @@ + + + + + + + + + diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml index a7b602cfb0f..d83fa595fb8 100644 --- a/res/xml/accessibility_settings.xml +++ b/res/xml/accessibility_settings.xml @@ -209,11 +209,11 @@ android:title="@string/accessibility_display_daltonizer_preference_title" settings:controller="com.android.settings.accessibility.DaltonizerPreferenceController"/> - diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index ee73e6fe02e..f184b982c96 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -172,7 +172,7 @@ public class AccessibilitySettings extends DashboardFragment { private SwitchPreference mToggleDisableAnimationsPreference; private Preference mDisplayMagnificationPreferenceScreen; private Preference mDisplayDaltonizerPreferenceScreen; - private SwitchPreference mToggleInversionPreference; + private Preference mToggleInversionPreference; private DevicePolicyManager mDpm; @@ -502,7 +502,8 @@ public class AccessibilitySettings extends DashboardFragment { mToggleInversionPreference.getOrder() + 1); mToggleDisableAnimationsPreference.setOrder( mToggleLargePointerIconPreference.getOrder() + 1); - mToggleInversionPreference.setSummary(R.string.summary_empty); + mToggleInversionPreference.setSummary(AccessibilityUtil.getSummary( + getContext(), Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED)); displayCategory.addPreference(mToggleInversionPreference); displayCategory.addPreference(mDisplayDaltonizerPreferenceScreen); } diff --git a/src/com/android/settings/accessibility/ColorInversionPreferenceController.java b/src/com/android/settings/accessibility/ColorInversionPreferenceController.java index 4e4c17b17a7..926bc0d0080 100644 --- a/src/com/android/settings/accessibility/ColorInversionPreferenceController.java +++ b/src/com/android/settings/accessibility/ColorInversionPreferenceController.java @@ -19,30 +19,21 @@ package com.android.settings.accessibility; import android.content.Context; import android.provider.Settings; -import androidx.annotation.VisibleForTesting; +import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.TogglePreferenceController; +/** Controller that shows the color inversion summary. */ +public class ColorInversionPreferenceController extends BasePreferenceController { -public class ColorInversionPreferenceController extends TogglePreferenceController { - @VisibleForTesting - static final int ON = 1; - @VisibleForTesting - static final int OFF = 0; + private static final String DISPLAY_INVERSION_ENABLED = + Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED; public ColorInversionPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); } @Override - public boolean isChecked() { - return Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, OFF) == ON; - } - - @Override - public boolean setChecked(boolean isChecked) { - return Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, (isChecked ? ON : OFF)); + public CharSequence getSummary() { + return AccessibilityUtil.getSummary(mContext, DISPLAY_INVERSION_ENABLED); } @Override diff --git a/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java new file mode 100644 index 00000000000..880efb6d135 --- /dev/null +++ b/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2019 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.app.Dialog; +import android.app.settings.SettingsEnums; +import android.content.DialogInterface; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.provider.Settings; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Switch; + +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.widget.SwitchBar; +import com.android.settingslib.search.SearchIndexable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +/** Settings page for color inversion. */ +@SearchIndexable +public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePreferenceFragment + implements SwitchBar.OnSwitchChangeListener, ShortcutPreference.OnClickListener { + + private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED; + private static final String PREVIEW_PREFERENCE_KEY = "color_inversion_preview"; + private static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference"; + private static final int DIALOG_ID_EDIT_SHORTCUT = 1; + private static final String DISPLAY_INVERSION_ENABLED = + Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED; + private final DialogInterface.OnClickListener mDialogListener = + (DialogInterface dialog, int id) -> { + if (id == DialogInterface.BUTTON_POSITIVE) { + // TODO(b/142531156): Save the shortcut type preference. + } + }; + private final Handler mHandler = new Handler(); + private Dialog mDialog; + private SettingsContentObserver mSettingsContentObserver; + + @Override + public void onStart() { + super.onStart(); + mSettingsContentObserver.register(getContentResolver()); + } + + @Override + public void onStop() { + mSettingsContentObserver.unregister(getContentResolver()); + super.onStop(); + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.ACCESSIBILITY_COLOR_INVERSION_SETTINGS; + } + + @Override + protected void onPreferenceToggled(String preferenceKey, boolean enabled) { + Settings.Secure.putInt(getContentResolver(), ENABLED, enabled ? State.OFF : State.ON); + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.accessibility_color_inversion_settings; + } + + @Override + protected void onRemoveSwitchBarToggleSwitch() { + super.onRemoveSwitchBarToggleSwitch(); + mSwitchBar.removeOnSwitchChangeListener(this); + } + + @Override + protected void updateSwitchBarText(SwitchBar switchBar) { + final String switchBarText = getString( + R.string.accessibility_display_inversion_switch_title, + getString(R.string.accessibility_display_inversion_switch_title)); + switchBar.setSwitchBarText(switchBarText, switchBarText); + } + + @Override + public void onSwitchChanged(Switch switchView, boolean isChecked) { + Settings.Secure.putInt(getContentResolver(), ENABLED, isChecked ? State.ON : State.OFF); + } + + @Override + protected void onInstallSwitchBarToggleSwitch() { + super.onInstallSwitchBarToggleSwitch(); + mSwitchBar.setCheckedInternal( + Settings.Secure.getInt(getContentResolver(), ENABLED, State.OFF) == State.ON); + mSwitchBar.addOnSwitchChangeListener(this); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + initShortcutPreference(); + final List shortcutFeatureKeys = new ArrayList<>(1); + shortcutFeatureKeys.add(DISPLAY_INVERSION_ENABLED); + mSettingsContentObserver = new SettingsContentObserver(mHandler, shortcutFeatureKeys) { + @Override + public void onChange(boolean selfChange, Uri uri) { + mSwitchBar.setCheckedInternal( + Settings.Secure.getInt(getContentResolver(), ENABLED, State.OFF) + == State.ON); + } + }; + return super.onCreateView(inflater, container, savedInstanceState); + } + + @Override + public Dialog onCreateDialog(int dialogId) { + if (dialogId == DIALOG_ID_EDIT_SHORTCUT) { + final CharSequence dialogTitle = getActivity().getString( + R.string.accessibility_shortcut_edit_dialog_title_daltonizer); + mDialog = AccessibilityEditDialogUtils.showEditShortcutDialog(getActivity(), + dialogTitle, mDialogListener); + } + + return mDialog; + } + + @Override + public int getDialogMetricsCategory(int dialogId) { + if (dialogId == DIALOG_ID_EDIT_SHORTCUT) { + return SettingsEnums.DIALOG_COLOR_INVERSION_EDIT_SHORTCUT; + } + return 0; + } + + private void initShortcutPreference() { + final PreferenceScreen preferenceScreen = getPreferenceScreen(); + final ShortcutPreference shortcutPreference = new ShortcutPreference( + preferenceScreen.getContext(), null); + final Preference previewPreference = findPreference(PREVIEW_PREFERENCE_KEY); + // Put the shortcutPreference before radioButtonPreference. + shortcutPreference.setPersistent(false); + shortcutPreference.setKey(getShortcutPreferenceKey()); + shortcutPreference.setOrder(previewPreference.getOrder() - 1); + shortcutPreference.setTitle(R.string.accessibility_shortcut_title); + shortcutPreference.setOnClickListener(this); + // TODO(b/142530063): Check the new setting key to decide which summary should be shown. + // TODO(b/142530063): Check if gesture mode is on to decide which summary should be shown. + // TODO(b/142530063): Check the new key to decide whether checkbox should be checked. + preferenceScreen.addPreference(shortcutPreference); + } + + public String getShortcutPreferenceKey() { + return KEY_SHORTCUT_PREFERENCE; + } + + @Override + public void onCheckboxClicked(ShortcutPreference preference) { + if (preference.getChecked()) { + // TODO(b/142530063): Enable shortcut when checkbox is checked. + } else { + // TODO(b/142530063): Disable shortcut when checkbox is unchecked. + } + } + + @Override + public void onSettingsClicked(ShortcutPreference preference) { + showDialog(DIALOG_ID_EDIT_SHORTCUT); + } + + @Retention(RetentionPolicy.SOURCE) + private @interface State { + int OFF = 0; + int ON = 1; + } + + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.accessibility_color_inversion_settings); +} diff --git a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java index 9fb93efd9cd..a4f3e62a987 100644 --- a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java @@ -47,8 +47,6 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe implements DaltonizerRadioButtonPreferenceController.OnChangeListener, SwitchBar.OnSwitchChangeListener, ShortcutPreference.OnClickListener { - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.accessibility_daltonizer_settings); private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED; private static final String RADIOPREFERENCE_KEY = "daltonizer_mode_deuteranomaly"; private static final int DIALOG_ID_EDIT_SHORTCUT = 1; @@ -206,4 +204,7 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe shortcutPreference.setOnClickListener(this); preferenceScreen.addPreference(shortcutPreference); } + + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.accessibility_daltonizer_settings); } diff --git a/tests/robotests/src/com/android/settings/accessibility/ColorInversionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ColorInversionPreferenceControllerTest.java index 6b46652e30f..e03449887d3 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ColorInversionPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ColorInversionPreferenceControllerTest.java @@ -16,82 +16,57 @@ package com.android.settings.accessibility; -import static com.android.settings.accessibility.ColorInversionPreferenceController.OFF; -import static com.android.settings.accessibility.ColorInversionPreferenceController.ON; - import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.provider.Settings; -import androidx.preference.SwitchPreference; - -import com.android.settings.core.BasePreferenceController; +import com.android.settings.R; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + @RunWith(RobolectricTestRunner.class) public class ColorInversionPreferenceControllerTest { - private static final int UNKNOWN = -1; + private static final String PREF_KEY = "toggle_inversion_preference"; + private static final String DISPLAY_INVERSION_ENABLED = + Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED; private Context mContext; private ColorInversionPreferenceController mController; - private SwitchPreference mPreference; @Before public void setUp() { - MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mController = new ColorInversionPreferenceController(mContext, "pref_key"); - mPreference = new SwitchPreference(mContext); - mController.updateState(mPreference); + mController = new ColorInversionPreferenceController(mContext, PREF_KEY); } @Test - public void getAvailabilityStatus_available() { - assertThat(mController.getAvailabilityStatus()).isEqualTo( - BasePreferenceController.AVAILABLE); - } - - @Test - public void isChecked_enabled() { + public void getSummary_enabledColorInversion_shouldReturnOnSummary() { Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, ON); + DISPLAY_INVERSION_ENABLED, State.ON); - mController.updateState(mPreference); - - assertThat(mController.isChecked()).isTrue(); - assertThat(mPreference.isChecked()).isTrue(); + assertThat(mController.getSummary().toString().contains( + mContext.getText(R.string.accessibility_feature_state_on))).isTrue(); } @Test - public void isChecked_disabled() { + public void getSummary_disabledColorInversion_shouldReturnOffSummary() { Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, OFF); + DISPLAY_INVERSION_ENABLED, State.OFF); - mController.updateState(mPreference); - - assertThat(mController.isChecked()).isFalse(); - assertThat(mPreference.isChecked()).isFalse(); + assertThat(mController.getSummary().toString().contains( + mContext.getText(R.string.accessibility_feature_state_off))).isTrue(); } - @Test - public void setChecked_enabled() { - mController.setChecked(true); - - assertThat(Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, UNKNOWN)).isEqualTo(ON); - } - - @Test - public void setChecked_disabled() { - mController.setChecked(false); - - assertThat(Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, UNKNOWN)).isEqualTo(OFF); + @Retention(RetentionPolicy.SOURCE) + private @interface State { + int OFF = 0; + int ON = 1; } }