diff --git a/res/values/strings.xml b/res/values/strings.xml index 32719495ab1..f6dcb624445 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5284,6 +5284,10 @@ Magnification Magnification shortcut + + Follow typing + + Magnification area automatically follows the text as you type About magnification diff --git a/src/com/android/settings/accessibility/MagnificationFollowTypingPreferenceController.java b/src/com/android/settings/accessibility/MagnificationFollowTypingPreferenceController.java new file mode 100644 index 00000000000..8757fdfaa43 --- /dev/null +++ b/src/com/android/settings/accessibility/MagnificationFollowTypingPreferenceController.java @@ -0,0 +1,80 @@ +/* + * 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.android.settings.accessibility.AccessibilityUtil.State.OFF; +import static com.android.settings.accessibility.AccessibilityUtil.State.ON; + +import android.content.Context; +import android.provider.Settings; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +import com.android.settings.R; +import com.android.settings.core.TogglePreferenceController; + +/** Controller that accesses and switches the preference status of following typing feature */ +public class MagnificationFollowTypingPreferenceController extends TogglePreferenceController + implements LifecycleObserver { + + static final String PREF_KEY = "magnification_follow_typing"; + + private SwitchPreference mFollowTypingPreference; + + public MagnificationFollowTypingPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public boolean isChecked() { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, ON) == ON; + } + + @Override + public boolean setChecked(boolean isChecked) { + return Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, + (isChecked ? ON : OFF)); + } + + @Override + public int getSliceHighlightMenuRes() { + return R.string.menu_key_accessibility; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mFollowTypingPreference = screen.findPreference(getPreferenceKey()); + } + + // TODO(b/186731461): Remove it when this controller is used in DashBoardFragment only. + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + void onResume() { + updateState(mFollowTypingPreference); + } +} diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java index 1586c5af56a..d1e9b565805 100644 --- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java @@ -40,6 +40,7 @@ import android.widget.CheckBox; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; +import androidx.preference.SwitchPreference; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.DialogCreatable; @@ -73,7 +74,6 @@ public class ToggleScreenMagnificationPreferenceFragment extends private static final TextUtils.SimpleStringSplitter sStringColonSplitter = new TextUtils.SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); - private MagnificationModePreferenceController mModePreferenceController; private DialogCreatable mDialogDelegate; @Override @@ -170,11 +170,28 @@ public class ToggleScreenMagnificationPreferenceFragment extends final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY); generalCategory.addPreference(mSettingsPreference); - mModePreferenceController = new MagnificationModePreferenceController(getContext(), - MagnificationModePreferenceController.PREF_KEY); - mModePreferenceController.setDialogHelper(this); - getSettingsLifecycle().addObserver(mModePreferenceController); - mModePreferenceController.displayPreference(getPreferenceScreen()); + final MagnificationModePreferenceController magnificationModePreferenceController = + new MagnificationModePreferenceController(getContext(), + MagnificationModePreferenceController.PREF_KEY); + magnificationModePreferenceController.setDialogHelper(this); + getSettingsLifecycle().addObserver(magnificationModePreferenceController); + magnificationModePreferenceController.displayPreference(getPreferenceScreen()); + + final SwitchPreference followingTypingSwitchPreference = + new SwitchPreference(getPrefContext()); + followingTypingSwitchPreference.setTitle( + R.string.accessibility_screen_magnification_follow_typing_title); + followingTypingSwitchPreference.setSummary( + R.string.accessibility_screen_magnification_follow_typing_summary); + followingTypingSwitchPreference.setKey( + MagnificationFollowTypingPreferenceController.PREF_KEY); + generalCategory.addPreference(followingTypingSwitchPreference); + + final MagnificationFollowTypingPreferenceController followTypingPreferenceController = + new MagnificationFollowTypingPreferenceController(getContext(), + MagnificationFollowTypingPreferenceController.PREF_KEY); + getSettingsLifecycle().addObserver(followTypingPreferenceController); + followTypingPreferenceController.displayPreference(getPreferenceScreen()); } @Override diff --git a/tests/robotests/src/com/android/settings/accessibility/MagnificationFollowTypingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/MagnificationFollowTypingPreferenceControllerTest.java new file mode 100644 index 00000000000..ccb66addd62 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/MagnificationFollowTypingPreferenceControllerTest.java @@ -0,0 +1,97 @@ +/* + * 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.android.settings.accessibility.AccessibilityUtil.State.OFF; +import static com.android.settings.accessibility.AccessibilityUtil.State.ON; + +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.provider.Settings; + +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class MagnificationFollowTypingPreferenceControllerTest { + + private static final String KEY_FOLLOW_TYPING = + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED; + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext)); + private final MagnificationFollowTypingPreferenceController mController = + new MagnificationFollowTypingPreferenceController(mContext, + MagnificationFollowTypingPreferenceController.PREF_KEY); + + @Before + public void setUp() { + final PreferenceManager preferenceManager = new PreferenceManager(mContext); + final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext); + mSwitchPreference.setKey(MagnificationFollowTypingPreferenceController.PREF_KEY); + screen.addPreference(mSwitchPreference); + mController.displayPreference(screen); + } + + @Test + public void isChecked_defaultStateForFollowTyping_onResumeShouldReturnTrue() { + mController.onResume(); + + assertThat(mController.isChecked()).isTrue(); + assertThat(mSwitchPreference.isChecked()).isTrue(); + } + + @Test + public void isChecked_enableFollowTyping_onResumeShouldReturnTrue() { + Settings.Secure.putInt(mContext.getContentResolver(), KEY_FOLLOW_TYPING, ON); + mController.onResume(); + + assertThat(mController.isChecked()).isTrue(); + assertThat(mSwitchPreference.isChecked()).isTrue(); + } + + @Test + public void isChecked_disableFollowTyping_onResumeShouldReturnFalse() { + Settings.Secure.putInt(mContext.getContentResolver(), KEY_FOLLOW_TYPING, OFF); + mController.onResume(); + + assertThat(mController.isChecked()).isFalse(); + assertThat(mSwitchPreference.isChecked()).isFalse(); + } + + @Test + public void performClick_switchDefaultStateForFollowTyping_shouldReturnFalse() { + mController.onResume(); + + mSwitchPreference.performClick(); + + verify(mSwitchPreference).setChecked(false); + assertThat(mController.isChecked()).isFalse(); + assertThat(mSwitchPreference.isChecked()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java index 9aa0e03f39e..10495c5f00a 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java @@ -49,6 +49,7 @@ import androidx.fragment.app.FragmentActivity; import androidx.preference.Preference; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; import com.android.settings.DialogCreatable; @@ -59,9 +60,9 @@ import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; @@ -88,23 +89,57 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { private static final String MAGNIFICATION_CONTROLLER_NAME = "com.android.server.accessibility.MagnificationController"; + private static final String KEY_FOLLOW_TYPING = + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED; + private TestToggleScreenMagnificationPreferenceFragment mFragment; private Context mContext; private Resources mResources; - private FragmentActivity mActivity; - @Before public void setUpTestFragment() { MockitoAnnotations.initMocks(this); mContext = spy(ApplicationProvider.getApplicationContext()); - mActivity = Robolectric.setupActivity(FragmentActivity.class); + final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class); mFragment = spy(new TestToggleScreenMagnificationPreferenceFragment(mContext)); mResources = spy(mContext.getResources()); when(mContext.getResources()).thenReturn(mResources); when(mFragment.getContext().getResources()).thenReturn(mResources); - doReturn(mActivity).when(mFragment).getActivity(); + doReturn(activity).when(mFragment).getActivity(); + } + + @Ignore("Ignore it since a NPE is happened in ShadowWindowManagerGlobal. (Ref. b/214161063)") + @Test + @Config(shadows = ShadowFragment.class) + public void onResume_defaultStateForFollowingTyping_switchPreferenceShouldReturnTrue() { + mFragment.onCreate(new Bundle()); + mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY); + mFragment.onAttach(mContext); + final SwitchPreference switchPreference = + mFragment.findPreference(MagnificationFollowTypingPreferenceController.PREF_KEY); + + mFragment.onResume(); + + assertThat(switchPreference).isNotNull(); + assertThat(switchPreference.isChecked()).isTrue(); + } + + @Ignore("Ignore it since a NPE is happened in ShadowWindowManagerGlobal. (Ref. b/214161063)") + @Test + @Config(shadows = ShadowFragment.class) + public void onResume_disableFollowingTyping_switchPreferenceShouldReturnFalse() { + Settings.Secure.putInt(mContext.getContentResolver(), KEY_FOLLOW_TYPING, OFF); + mFragment.onCreate(new Bundle()); + mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY); + mFragment.onAttach(mContext); + SwitchPreference switchPreference = + mFragment.findPreference(MagnificationFollowTypingPreferenceController.PREF_KEY); + + mFragment.onResume(); + + assertThat(switchPreference).isNotNull(); + assertThat(switchPreference.isChecked()).isFalse(); } @Test @@ -267,6 +302,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { assertThat(expectedType).isEqualTo(UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP); } + @Ignore("Ignore it since a NPE is happened in ShadowWindowManagerGlobal. (Ref. b/214161063)") @Test public void onCreateView_notSupportsMagnificationArea_settingsPreferenceIsNull() { when(mResources.getBoolean( @@ -278,13 +314,16 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { assertThat(mFragment.mSettingsPreference).isNull(); } + @Ignore("Ignore it since a NPE is happened in ShadowWindowManagerGlobal. (Ref. b/214161063)") @Test public void onCreateView_setDialogDelegateAndAddTheControllerToLifeCycleObserver() { + Lifecycle lifecycle = mock(Lifecycle.class); + when(mFragment.getSettingsLifecycle()).thenReturn(lifecycle); + mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY); verify(mFragment).setDialogDelegate(any(MagnificationModePreferenceController.class)); - verify(mFragment.mSpyLifeyCycle).addObserver( - any(MagnificationModePreferenceController.class)); + verify(lifecycle).addObserver(any(MagnificationModePreferenceController.class)); } @Test @@ -331,8 +370,6 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { static class TestToggleScreenMagnificationPreferenceFragment extends ToggleScreenMagnificationPreferenceFragment { - private final Lifecycle mSpyLifeyCycle = Mockito.mock(Lifecycle.class); - private final Context mContext; private final PreferenceManager mPreferenceManager; @@ -401,11 +438,6 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { // UI related function, do nothing in tests } - @Override - public Lifecycle getSettingsLifecycle() { - return mSpyLifeyCycle; - } - @Override public Context getContext() { return mContext;