From 46369353edb534fff3d7fe91c4999e64ba44538c Mon Sep 17 00:00:00 2001 From: Isaac Chai Date: Wed, 21 Feb 2024 14:54:32 +0000 Subject: [PATCH] Adding Settings preference for single finger panning feature Test: Locally tested on device + MagnificationOneFingerPanningPreferenceControllerTest Bug: 282039824 Change-Id: I1d1a649060cba862c8f333e6e76184fade2dcdce --- res/values/strings.xml | 8 + ...nOneFingerPanningPreferenceController.java | 102 ++++++++++ ...ScreenMagnificationPreferenceFragment.java | 19 ++ ...FingerPanningPreferenceControllerTest.java | 187 ++++++++++++++++++ 4 files changed, 316 insertions(+) create mode 100644 src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 7ae9074242a..8b0cd67d331 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4760,6 +4760,14 @@ Cancel Magnification settings + + One-finger panning + + Move the magnification area by dragging one finger. + + Move the magnification area by dragging two fingers. Magnify with shortcut diff --git a/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceController.java b/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceController.java new file mode 100644 index 00000000000..a2ce948994d --- /dev/null +++ b/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceController.java @@ -0,0 +1,102 @@ +/* + * 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.android.settings.accessibility.AccessibilityUtil.State.OFF; +import static com.android.settings.accessibility.AccessibilityUtil.State.ON; + +import android.content.Context; +import android.content.res.Resources; +import android.provider.Settings; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.preference.PreferenceScreen; +import androidx.preference.TwoStatePreference; + +import com.android.server.accessibility.Flags; +import com.android.settings.R; +import com.android.settings.core.TogglePreferenceController; + +public class MagnificationOneFingerPanningPreferenceController + extends TogglePreferenceController { + static final String PREF_KEY = Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED; + + @Nullable + private TwoStatePreference mSwitchPreference; + + @VisibleForTesting + final boolean mDefaultValue; + + public MagnificationOneFingerPanningPreferenceController(Context context) { + super(context, PREF_KEY); + boolean defaultValue; + try { + defaultValue = context.getResources().getBoolean( + com.android.internal.R.bool.config_enable_a11y_magnification_single_panning); + } catch (Resources.NotFoundException e) { + defaultValue = false; + } + mDefaultValue = defaultValue; + } + + @Override + public int getAvailabilityStatus() { + return (Flags.enableMagnificationOneFingerPanningGesture()) + ? AVAILABLE : DISABLED_FOR_USER; + } + + @Override + public boolean isChecked() { + return Settings.Secure.getInt( + mContext.getContentResolver(), + PREF_KEY, + (mDefaultValue) ? ON : OFF) == ON; + } + + @Override + public boolean setChecked(boolean isChecked) { + var toReturn = Settings.Secure.putInt(mContext.getContentResolver(), + PREF_KEY, + (isChecked ? ON : OFF)); + if (mSwitchPreference != null) { + refreshSummary(mSwitchPreference); + } + return toReturn; + } + + @Override + public CharSequence getSummary() { + return (isChecked()) + ? mContext.getString( + R.string.accessibility_magnification_one_finger_panning_summary_on) + : mContext.getString( + R.string.accessibility_magnification_one_finger_panning_summary_off); + } + + @Override + public int getSliceHighlightMenuRes() { + return R.string.menu_key_accessibility; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mSwitchPreference = screen.findPreference(getPreferenceKey()); + refreshSummary(mSwitchPreference); + } +} diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java index d9baa03d177..985d45d89c2 100644 --- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java @@ -200,6 +200,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY); generalCategory.addPreference(mSettingsPreference); + addOneFingerPanningSetting(generalCategory); final MagnificationModePreferenceController magnificationModePreferenceController = new MagnificationModePreferenceController(getContext(), MagnificationModePreferenceController.PREF_KEY); @@ -283,6 +284,24 @@ public class ToggleScreenMagnificationPreferenceFragment extends addPreferenceController(alwaysOnPreferenceController); } + private void addOneFingerPanningSetting(PreferenceCategory generalCategory) { + if (!Flags.enableMagnificationOneFingerPanningGesture()) { + return; + } + + var oneFingerPanningPreference = new SwitchPreferenceCompat(getPrefContext()); + oneFingerPanningPreference.setTitle( + R.string.accessibility_magnification_one_finger_panning_title); + oneFingerPanningPreference.setKey( + MagnificationOneFingerPanningPreferenceController.PREF_KEY); + generalCategory.addPreference(oneFingerPanningPreference); + + var oneFingerPanningPreferenceController = + new MagnificationOneFingerPanningPreferenceController(getContext()); + oneFingerPanningPreferenceController.displayPreference(getPreferenceScreen()); + addPreferenceController(oneFingerPanningPreferenceController); + } + private void addJoystickSetting(PreferenceCategory generalCategory) { if (!DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_WINDOW_MANAGER, diff --git a/tests/robotests/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceControllerTest.java new file mode 100644 index 00000000000..326a7a04a20 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceControllerTest.java @@ -0,0 +1,187 @@ +/* + * 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.android.server.accessibility.Flags.enableMagnificationOneFingerPanningGesture; +import static com.android.settings.accessibility.AccessibilityUtil.State.OFF; +import static com.android.settings.accessibility.AccessibilityUtil.State.ON; +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_FOR_USER; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.platform.test.flag.junit.SetFlagsRule; +import android.provider.Settings; + +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; +import androidx.test.core.app.ApplicationProvider; + +import com.android.server.accessibility.Flags; +import com.android.settings.R; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class MagnificationOneFingerPanningPreferenceControllerTest { + private static final String ONE_FINGER_PANNING_KEY = + Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED; + + @Rule public final SetFlagsRule mSetFlagsRule = + new SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT); + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext)); + private final MagnificationOneFingerPanningPreferenceController mController = + new MagnificationOneFingerPanningPreferenceController(mContext); + + private PreferenceScreen mScreen; + + @Before + public void setUp() { + final PreferenceManager preferenceManager = new PreferenceManager(mContext); + mScreen = preferenceManager.createPreferenceScreen(mContext); + mSwitchPreference.setKey(MagnificationOneFingerPanningPreferenceController.PREF_KEY); + mScreen.addPreference(mSwitchPreference); + mController.displayPreference(mScreen); + } + + @After + public void cleanup() { + // Can't use resetToDefaults as it NPE with + // "Cannot invoke "android.content.IContentProvider.call" + Settings.Secure.putInt( + mContext.getContentResolver(), + MagnificationOneFingerPanningPreferenceController.PREF_KEY, + (mController.mDefaultValue) ? ON : OFF); + } + + @Test + public void displayPreference_defaultState_correctSummarySet() { + assertThat(mSwitchPreference.getSummary()) + .isEqualTo(mContext.getString( + R.string.accessibility_magnification_one_finger_panning_summary_off)); + } + + @Test + public void getAvailabilityStatus_defaultState_disabled() { + int status = mController.getAvailabilityStatus(); + + assertThat(status).isEqualTo(DISABLED_FOR_USER); + } + + @Test + public void getAvailabilityStatus_featureFlagEnabled_enabled() { + enableFlag(); + + int status = mController.getAvailabilityStatus(); + + assertThat(status).isEqualTo(AVAILABLE); + } + + @Test + public void isChecked_defaultState_returnFalse() { + assertThat(mController.isChecked()).isFalse(); + assertThat(mSwitchPreference.isChecked()).isFalse(); + } + + @Test + public void isChecked_settingsEnabled_returnTrue() { + Settings.Secure.putInt(mContext.getContentResolver(), ONE_FINGER_PANNING_KEY, ON); + + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void isChecked_settingsDisabled_returnTrue() { + Settings.Secure.putInt(mContext.getContentResolver(), ONE_FINGER_PANNING_KEY, OFF); + + assertThat(mController.isChecked()).isFalse(); + } + + @Test + public void setChecked_enabled_enabledSummarySet() { + mController.setChecked(true); + + assertThat(mSwitchPreference.getSummary()).isEqualTo(enabledSummary()); + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void setChecked_disabled_disabledSummarySet() { + mController.setChecked(false); + + assertThat(mController.isChecked()).isFalse(); + assertThat(mSwitchPreference.getSummary()).isEqualTo(disabledSummary()); + } + + @Test + public void getSummary_disable_disableSummaryTextUsed() { + Settings.Secure.putInt(mContext.getContentResolver(), ONE_FINGER_PANNING_KEY, OFF); + + var summary = mController.getSummary(); + + assertThat(summary).isEqualTo(disabledSummary()); + } + + @Test + public void getSummary_enable_enabledSummaryTextUsed() { + Settings.Secure.putInt(mContext.getContentResolver(), ONE_FINGER_PANNING_KEY, ON); + + var summary = mController.getSummary(); + + assertThat(summary).isEqualTo(enabledSummary()); + } + + @Test + public void performClick_switchDefaultState_shouldReturnTrue() { + enableFlag(); + + mSwitchPreference.performClick(); + + verify(mSwitchPreference).setChecked(true); + assertThat(mController.isChecked()).isTrue(); + assertThat(mSwitchPreference.isChecked()).isTrue(); + } + + private void enableFlag() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE); + assertThat(enableMagnificationOneFingerPanningGesture()).isTrue(); + // This ensures that preference change listeners are added correctly. + mController.displayPreference(mScreen); + } + + private String enabledSummary() { + return mContext.getString( + R.string.accessibility_magnification_one_finger_panning_summary_on); + } + + private String disabledSummary() { + return mContext.getString( + R.string.accessibility_magnification_one_finger_panning_summary_off); + } +}