diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 8df986f8cbb..eb2b869995a 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -1014,19 +1014,19 @@ \? - - - @string/daltonizer_mode_deuteranomaly - @string/daltonizer_mode_protanomaly - @string/daltonizer_mode_tritanomaly + + + daltonizer_mode_deuteranomaly + daltonizer_mode_protanomaly + daltonizer_mode_tritanomaly - + 12 11 13 - + diff --git a/res/values/strings.xml b/res/values/strings.xml index 43018c55190..d9020e8375c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4922,6 +4922,18 @@ Show in Quick Settings Correction mode + + Red-green + + Green-red + + Blue-yellow + + Deuteranomaly + + Protanomaly + + Tritanomaly diff --git a/res/xml/accessibility_daltonizer_settings.xml b/res/xml/accessibility_daltonizer_settings.xml index 496c51571b9..22e05101b0d 100644 --- a/res/xml/accessibility_daltonizer_settings.xml +++ b/res/xml/accessibility_daltonizer_settings.xml @@ -18,19 +18,32 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:key="daltonizer_preference_screen" + android:persistent="false" android:title="@string/accessibility_display_daltonizer_preference_title"> - + + + + + + android:title="@string/accessibility_display_daltonizer_preference_subtitle" + settings:searchable="false" /> diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml index e13e820a460..a7b602cfb0f 100644 --- a/res/xml/accessibility_settings.xml +++ b/res/xml/accessibility_settings.xml @@ -18,68 +18,78 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:key="accessibility_settings_screen" - android:title="@string/accessibility_settings" - android:persistent="true"> + android:persistent="false" + android:title="@string/accessibility_settings"> - + android:persistent="false" + android:title="@string/user_installed_services_category_title"/> - - - @@ -87,111 +97,124 @@ - + + android:key="gesture_system_navigation_input_summary_accessibility" + android:persistent="false" + android:title="@string/system_navigation_title" + settings:controller="com.android.settings.gestures.SystemNavigationPreferenceController"/> + diff --git a/src/com/android/settings/accessibility/DaltonizerPreferenceController.java b/src/com/android/settings/accessibility/DaltonizerPreferenceController.java index c02a3622e79..efdfaed2e88 100644 --- a/src/com/android/settings/accessibility/DaltonizerPreferenceController.java +++ b/src/com/android/settings/accessibility/DaltonizerPreferenceController.java @@ -16,25 +16,143 @@ package com.android.settings.accessibility; +import android.content.ContentResolver; import android.content.Context; +import android.content.res.Resources; import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; +import androidx.lifecycle.LifecycleObserver; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.RadioButtonPreference; -public class DaltonizerPreferenceController extends BasePreferenceController { +import com.google.common.primitives.Ints; - public DaltonizerPreferenceController(Context context, String preferenceKey) { +import java.util.HashMap; +import java.util.Map; + +/** Controller class that control accessibility daltonizer settings. */ +public class DaltonizerPreferenceController extends BasePreferenceController implements + LifecycleObserver, RadioButtonPreference.OnClickListener { + private static final String TYPE = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER; + + // pair the preference key and daltonizer value. + private final Map mAccessibilityDaltonizerKeyToValueMap = new HashMap<>(); + + // RadioButtonPreference key, each preference represent a daltonizer value. + private final ContentResolver mContentResolver; + private final Resources mResources; + private DaltonizerPreferenceController.OnChangeListener mOnChangeListener; + private RadioButtonPreference mPreference; + private int mAccessibilityDaltonizerValue; + + public DaltonizerPreferenceController(Context context, Lifecycle lifecycle, + String preferenceKey) { super(context, preferenceKey); + + mContentResolver = context.getContentResolver(); + mResources = context.getResources(); + + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + protected static int getSecureAccessibilityDaltonizerValue(ContentResolver resolver, + String name) { + final String daltonizerStringValue = Settings.Secure.getString(resolver, name); + if (daltonizerStringValue == null) { + return AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY; + } + final Integer daltonizerIntValue = Ints.tryParse(daltonizerStringValue); + return daltonizerIntValue == null ? AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY + : daltonizerIntValue; + } + + public void setOnChangeListener(DaltonizerPreferenceController.OnChangeListener listener) { + mOnChangeListener = listener; + } + + private Map getDaltonizerValueToKeyMap() { + if (mAccessibilityDaltonizerKeyToValueMap.size() == 0) { + + final String[] daltonizerKeys = mResources.getStringArray( + R.array.daltonizer_mode_keys); + + final int[] daltonizerValues = mResources.getIntArray( + R.array.daltonizer_type_values); + + final int daltonizerValueCount = daltonizerValues.length; + for (int i = 0; i < daltonizerValueCount; i++) { + mAccessibilityDaltonizerKeyToValueMap.put(daltonizerKeys[i], daltonizerValues[i]); + } + } + return mAccessibilityDaltonizerKeyToValueMap; + } + + private void putSecureString(String name, String value) { + Settings.Secure.putString(mContentResolver, name, value); + } + + private void handlePreferenceChange(String value) { + putSecureString(TYPE, value); } @Override public int getAvailabilityStatus() { - return AVAILABLE_UNSEARCHABLE; + return AVAILABLE; } @Override - public CharSequence getSummary() { - return AccessibilityUtil.getSummary(mContext, - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED); + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = (RadioButtonPreference) + screen.findPreference(getPreferenceKey()); + mPreference.setOnClickListener(this); + updateState(mPreference); } + + @Override + public void onRadioButtonClicked(RadioButtonPreference preference) { + final int value = getDaltonizerValueToKeyMap().get(mPreferenceKey); + handlePreferenceChange(String.valueOf(value)); + if (mOnChangeListener != null) { + mOnChangeListener.onCheckedChanged(mPreference); + } + } + + private int getAccessibilityDaltonizerValue() { + final int daltonizerValue = getSecureAccessibilityDaltonizerValue(mContentResolver, + TYPE); + return daltonizerValue; + } + + protected void updatePreferenceCheckedState(int value) { + if (mAccessibilityDaltonizerValue == value) { + mPreference.setChecked(true); + } + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + mAccessibilityDaltonizerValue = getAccessibilityDaltonizerValue(); + + // reset RadioButton + mPreference.setChecked(false); + final int preferenceValue = getDaltonizerValueToKeyMap().get(mPreference.getKey()); + updatePreferenceCheckedState(preferenceValue); + } + + /** Listener interface handles checked event. */ + public interface OnChangeListener { + /** A hook that is called when preference checked.*/ + void onCheckedChanged(Preference preference); + } + } \ No newline at end of file diff --git a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java index e02a74a59bd..f127b530e4f 100644 --- a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java @@ -18,34 +18,56 @@ package com.android.settings.accessibility; import android.app.settings.SettingsEnums; import android.content.Context; -import android.hardware.display.ColorDisplayManager; -import android.os.Bundle; -import android.provider.SearchIndexableResource; +import android.content.res.Resources; import android.provider.Settings; -import android.view.accessibility.AccessibilityManager; import android.widget.Switch; -import androidx.preference.ListPreference; import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; import com.android.settings.widget.SwitchBar; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.search.SearchIndexable; import java.util.ArrayList; import java.util.List; @SearchIndexable -public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceFragment - implements Preference.OnPreferenceChangeListener, SwitchBar.OnSwitchChangeListener { - private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED; - private static final String TYPE = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER; - private static final int DEFAULT_TYPE = AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY; - private static final String KEY_DALTONIZER_FOOTER = "daltonizer_footer"; +public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceFragment + implements DaltonizerPreferenceController.OnChangeListener, + SwitchBar.OnSwitchChangeListener { - private ListPreference mType; + private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED; + + private static final List sControllers = new ArrayList<>(); + + @Override + public void onCheckedChanged(Preference preference) { + for (AbstractPreferenceController controller : sControllers) { + controller.updateState(preference); + } + } + + @Override + public void onResume() { + super.onResume(); + for (AbstractPreferenceController controller : + buildPreferenceControllers(getPrefContext(), getSettingsLifecycle())) { + ((DaltonizerPreferenceController) controller).setOnChangeListener(this); + ((DaltonizerPreferenceController) controller).displayPreference(getPreferenceScreen()); + } + } + + @Override + public void onPause() { + super.onPause(); + for (AbstractPreferenceController controller : + buildPreferenceControllers(getPrefContext(), getSettingsLifecycle())) { + ((DaltonizerPreferenceController) controller).setOnChangeListener(null); + } + } @Override public int getMetricsCategory() { @@ -57,16 +79,6 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF return R.string.help_url_color_correction; } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mType = (ListPreference) findPreference("type"); - - final Preference footer = findPreference(KEY_DALTONIZER_FOOTER); - footer.setVisible(!ColorDisplayManager.isColorTransformAccelerated(getActivity())); - initPreferences(); - } @Override protected int getPreferenceScreenResId() { @@ -75,26 +87,7 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF @Override protected void onPreferenceToggled(String preferenceKey, boolean enabled) { - Settings.Secure.putInt(getContentResolver(), ENABLED, enabled ? 1 : 0); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == mType) { - Settings.Secure.putInt(getContentResolver(), TYPE, Integer.parseInt((String) newValue)); - preference.setSummary("%s"); - } - - return true; - } - - @Override - protected void onInstallSwitchBarToggleSwitch() { - super.onInstallSwitchBarToggleSwitch(); - - mSwitchBar.setCheckedInternal( - Settings.Secure.getInt(getContentResolver(), ENABLED, 0) == 1); - mSwitchBar.addOnSwitchChangeListener(this); + Settings.Secure.putInt(getContentResolver(), ENABLED, enabled ? 0 : 1); } @Override @@ -110,25 +103,34 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF switchBar.setSwitchBarText(switchBarText, switchBarText); } - private void initPreferences() { - final String value = Integer.toString( - Settings.Secure.getInt(getContentResolver(), TYPE, DEFAULT_TYPE)); - mType.setValue(value); - mType.setOnPreferenceChangeListener(this); - final int index = mType.findIndexOfValue(value); - if (index < 0) { - // We're using a mode controlled by developer preferences. - mType.setSummary(getString(R.string.daltonizer_type_overridden, - getString(R.string.simulate_color_space))); - } + @Override + public void onSwitchChanged(Switch switchView, boolean isChecked) { + Settings.Secure.putInt(getContentResolver(), ENABLED, isChecked ? 1 : 0); } @Override - public void onSwitchChanged(Switch switchView, boolean isChecked) { - onPreferenceToggled(mPreferenceKey, isChecked); + protected void onInstallSwitchBarToggleSwitch() { + super.onInstallSwitchBarToggleSwitch(); + mSwitchBar.setCheckedInternal( + Settings.Secure.getInt(getContentResolver(), ENABLED, 0) == 1); + mSwitchBar.addOnSwitchChangeListener(this); + } + + private static List buildPreferenceControllers(Context context, + Lifecycle lifecycle) { + if (sControllers.size() == 0) { + final Resources resources = context.getResources(); + final String[] daltonizerKeys = resources.getStringArray( + R.array.daltonizer_mode_keys); + + for (int i = 0; i < daltonizerKeys.length; i++) { + sControllers.add(new DaltonizerPreferenceController( + context, lifecycle, daltonizerKeys[i])); + } + } + return sControllers; } 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/DaltonizerPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/DaltonizerPreferenceControllerTest.java index e236cd4bbc4..86520a817e2 100644 --- a/tests/robotests/src/com/android/settings/accessibility/DaltonizerPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/DaltonizerPreferenceControllerTest.java @@ -18,53 +18,100 @@ package com.android.settings.accessibility; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; -import com.android.settings.R; -import com.android.settings.core.BasePreferenceController; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.RadioButtonPreference; 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 org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) -public class DaltonizerPreferenceControllerTest { - private static final int ON = 1; - private static final int OFF = 0; +public class DaltonizerPreferenceControllerTest implements + DaltonizerPreferenceController.OnChangeListener { + private static final String PREF_KEY = "daltonizer_mode_protanomaly"; + private static final String PREF_VALUE = "11"; + private static final String PREF_FAKE_VALUE = "-1"; - private Context mContext; private DaltonizerPreferenceController mController; + @Mock + private RadioButtonPreference mMockPref; + private Context mContext; + private ContentResolver mContentResolver; + + @Mock + private PreferenceScreen mScreen; + @Before public void setUp() { + MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mController = new DaltonizerPreferenceController(mContext, "color_correction"); + mController = new DaltonizerPreferenceController(mContext, mock(Lifecycle.class), PREF_KEY); + mController.setOnChangeListener(this); + mContentResolver = mContext.getContentResolver(); + + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mMockPref); + when(mMockPref.getKey()).thenReturn(PREF_KEY); + mController.displayPreference(mScreen); + } + + @Override + public void onCheckedChanged(Preference preference) { + mController.updateState(preference); } @Test - public void getAvailabilityStatus_shouldReturnAvailableUnsearchable() { - assertThat(mController.getAvailabilityStatus()) - .isEqualTo(BasePreferenceController.AVAILABLE_UNSEARCHABLE); + public void isAvailable() { + assertThat(mController.isAvailable()).isTrue(); } @Test - public void getSummary_enabledColorCorrection_shouldReturnOnSummary() { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, ON); + public void updateState_notChecked() { + Settings.Secure.putString(mContentResolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, PREF_FAKE_VALUE); - assertThat(mController.getSummary()) - .isEqualTo(mContext.getText(R.string.accessibility_feature_state_on)); + mController.updateState(mMockPref); + + // the first checked state is set to false by control + verify(mMockPref, atLeastOnce()).setChecked(false); + verify(mMockPref, never()).setChecked(true); } @Test - public void getSummary_disabledColorCorrection_shouldReturnOffSummary() { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, OFF); + public void updateState_checked() { + Settings.Secure.putString(mContentResolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, PREF_VALUE); - assertThat(mController.getSummary()) - .isEqualTo(mContext.getText(R.string.accessibility_feature_state_off)); + mController.updateState(mMockPref); + + // the first checked state is set to false by control + verify(mMockPref, atLeastOnce()).setChecked(false); + verify(mMockPref, atLeastOnce()).setChecked(true); + } + + @Test + public void onRadioButtonClick_shouldReturnDaltonizerValue() { + mController.onRadioButtonClicked(mMockPref); + final String accessibilityDaltonizerValue = Settings.Secure.getString(mContentResolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER); + + assertThat(accessibilityDaltonizerValue).isEqualTo(PREF_VALUE); } }