diff --git a/res/xml/accessibility_text_reading_options.xml b/res/xml/accessibility_text_reading_options.xml index 4bc93173e0c..49f697328c4 100644 --- a/res/xml/accessibility_text_reading_options.xml +++ b/res/xml/accessibility_text_reading_options.xml @@ -21,6 +21,16 @@ android:persistent="false" android:title="@string/accessibility_text_reading_options_title"> + + { + private static final float FONT_SCALE_DEF_VALUE = 1.0f; + + FontSizeData(Context context) { + super(context); + + final Resources resources = getContext().getResources(); + final ContentResolver resolver = getContext().getContentResolver(); + final List strEntryValues = + Arrays.asList(resources.getStringArray(R.array.entryvalues_font_size)); + setDefaultValue(FONT_SCALE_DEF_VALUE); + final float currentScale = + Settings.System.getFloat(resolver, Settings.System.FONT_SCALE, getDefaultValue()); + setInitialIndex(fontSizeValueToIndex(currentScale, strEntryValues.toArray(new String[0]))); + setValues(strEntryValues.stream().map(Float::valueOf).collect(Collectors.toList())); + } + + @Override + void commit(int currentProgress) { + final ContentResolver resolver = getContext().getContentResolver(); + Settings.System.putFloat(resolver, Settings.System.FONT_SCALE, + getValues().get(currentProgress)); + } +} diff --git a/src/com/android/settings/accessibility/PreviewSizeData.java b/src/com/android/settings/accessibility/PreviewSizeData.java new file mode 100644 index 00000000000..5d4204e2e56 --- /dev/null +++ b/src/com/android/settings/accessibility/PreviewSizeData.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 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 java.util.List; + +/** + * Abstract data class for storing and fetching the configurations related to the preview of the + * text and reading options. + */ +abstract class PreviewSizeData { + private final Context mContext; + private int mInitialIndex; + private T mDefaultValue; + private List mValues; + + PreviewSizeData(@NonNull Context context) { + mContext = context; + } + + Context getContext() { + return mContext; + } + + List getValues() { + return mValues; + } + + void setValues(List values) { + mValues = values; + } + + T getDefaultValue() { + return mDefaultValue; + } + + void setDefaultValue(T defaultValue) { + mDefaultValue = defaultValue; + } + + int getInitialIndex() { + return mInitialIndex; + } + + void setInitialIndex(int initialIndex) { + mInitialIndex = initialIndex; + } + + /** + * Persists the selected size. + */ + abstract void commit(int currentProgress); +} diff --git a/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java b/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java new file mode 100644 index 00000000000..be10c77f0d1 --- /dev/null +++ b/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2022 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 android.widget.SeekBar; + +import androidx.annotation.NonNull; +import androidx.preference.PreferenceScreen; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.widget.LabeledSeekBarPreference; + +/** + * The controller of {@link LabeledSeekBarPreference} that listens to display size and font size + * settings changes and updates preview size threshold smoothly. + */ +class PreviewSizeSeekBarController extends BasePreferenceController { + private final PreviewSizeData mSizeData; + private boolean mSeekByTouch; + private ProgressInteractionListener mInteractionListener; + + private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = + new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + mInteractionListener.notifyPreferenceChanged(); + + if (!mSeekByTouch && mInteractionListener != null) { + mInteractionListener.onProgressChanged(); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + mSeekByTouch = true; + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + mSeekByTouch = false; + + if (mInteractionListener != null) { + mInteractionListener.onEndTrackingTouch(); + } + } + }; + + PreviewSizeSeekBarController(Context context, String preferenceKey, + @NonNull PreviewSizeData sizeData) { + super(context, preferenceKey); + mSizeData = sizeData; + } + + void setInteractionListener(ProgressInteractionListener interactionListener) { + mInteractionListener = interactionListener; + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + + final int dataSize = mSizeData.getValues().size(); + final int initialIndex = mSizeData.getInitialIndex(); + final LabeledSeekBarPreference seekBarPreference = + screen.findPreference(getPreferenceKey()); + + seekBarPreference.setMax(dataSize - 1); + seekBarPreference.setProgress(initialIndex); + seekBarPreference.setContinuousUpdates(true); + seekBarPreference.setOnSeekBarChangeListener(mSeekBarChangeListener); + } + + /** + * Interface for callbacks when users interact with the seek bar. + */ + interface ProgressInteractionListener { + + /** + * Called when the progress is changed. + */ + void notifyPreferenceChanged(); + + /** + * Called when the progress is changed without tracking touch. + */ + void onProgressChanged(); + + /** + * Called when the seek bar is end tracking. + */ + void onEndTrackingTouch(); + } +} diff --git a/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java b/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java index 0e8457beaca..9bf5a146754 100644 --- a/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java +++ b/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java @@ -17,12 +17,17 @@ package com.android.settings.accessibility; import android.app.settings.SettingsEnums; +import android.content.Context; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.search.SearchIndexable; +import java.util.ArrayList; +import java.util.List; + /** * Accessibility settings for adjusting the system features which are related to the reading. For * example, bold text, high contrast text, display size, font size and so on. @@ -30,6 +35,7 @@ import com.android.settingslib.search.SearchIndexable; @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) public class TextReadingPreferenceFragment extends DashboardFragment { private static final String TAG = "TextReadingPreferenceFragment"; + private static final String FONT_SIZE_KEY = "font_size"; @Override protected int getPreferenceScreenResId() { @@ -46,6 +52,16 @@ public class TextReadingPreferenceFragment extends DashboardFragment { return SettingsEnums.ACCESSIBILITY_TEXT_READING_OPTIONS; } + @Override + protected List createPreferenceControllers(Context context) { + final List controllers = new ArrayList<>(); + final FontSizeData fontSizeData = new FontSizeData(context); + + controllers.add(new PreviewSizeSeekBarController(context, FONT_SIZE_KEY, fontSizeData)); + + return controllers; + } + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.accessibility_text_reading_options); } diff --git a/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java b/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java new file mode 100644 index 00000000000..7e357140811 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 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.provider.Settings; + +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +/** + * Tests for {@link FontSizeData}. + */ +@RunWith(RobolectricTestRunner.class) +public class FontSizeDataTest { + private final Context mContext = ApplicationProvider.getApplicationContext(); + private FontSizeData mFontSizeData; + + @Before + public void setUp() { + mFontSizeData = new FontSizeData(mContext); + } + + @Test + public void commit_success() { + final int progress = 3; + + mFontSizeData.commit(progress); + final float currentScale = + Settings.System.getFloat(mContext.getContentResolver(), Settings.System.FONT_SCALE, + /* def= */ 1.0f); + + assertThat(currentScale).isEqualTo(mFontSizeData.getValues().get(progress)); + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java new file mode 100644 index 00000000000..a67b001f85c --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2022 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.anyString; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; + +import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.widget.LabeledSeekBarPreference; + +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; + +/** + * Tests for {@link PreviewSizeSeekBarController}. + */ +@RunWith(RobolectricTestRunner.class) +public class PreviewSizeSeekBarControllerTest { + private static final String FONT_SIZE_KEY = "font_size"; + private final Context mContext = ApplicationProvider.getApplicationContext(); + private PreviewSizeSeekBarController mSeekBarController; + private FontSizeData mFontSizeData; + private LabeledSeekBarPreference mSeekBarPreference; + + @Mock + private PreferenceScreen mPreferenceScreen; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mFontSizeData = new FontSizeData(mContext); + + mSeekBarController = + new PreviewSizeSeekBarController(mContext, FONT_SIZE_KEY, mFontSizeData); + + mSeekBarPreference = spy(new LabeledSeekBarPreference(mContext, /* attrs= */ null)); + when(mPreferenceScreen.findPreference(anyString())).thenReturn(mSeekBarPreference); + } + + @Test + public void initMax_matchResult() { + when(mPreferenceScreen.findPreference(anyString())).thenReturn(mSeekBarPreference); + + mSeekBarController.displayPreference(mPreferenceScreen); + + assertThat(mSeekBarPreference.getMax()).isEqualTo( + mFontSizeData.getValues().size() - 1); + } + + @Test + public void initProgress_matchResult() { + when(mPreferenceScreen.findPreference(anyString())).thenReturn(mSeekBarPreference); + + mSeekBarController.displayPreference(mPreferenceScreen); + + verify(mSeekBarPreference).setProgress(mFontSizeData.getInitialIndex()); + } +}