diff --git a/res/values/strings.xml b/res/values/strings.xml index bf30734c6df..4ee7c0e8971 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4814,6 +4814,8 @@ Move the magnification area by dragging two fingers. + + Unavailable while only magnifying part of the screen Magnify with shortcut diff --git a/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceController.java b/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceController.java index a2ce948994d..4eb5090dce6 100644 --- a/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceController.java +++ b/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceController.java @@ -21,27 +21,43 @@ import static com.android.settings.accessibility.AccessibilityUtil.State.ON; import android.content.Context; import android.content.res.Resources; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.preference.TwoStatePreference; -import com.android.server.accessibility.Flags; import com.android.settings.R; +import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode; import com.android.settings.core.TogglePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnPause; +import com.android.settingslib.core.lifecycle.events.OnResume; public class MagnificationOneFingerPanningPreferenceController - extends TogglePreferenceController { + extends TogglePreferenceController implements LifecycleObserver, OnResume, OnPause { static final String PREF_KEY = Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED; - @Nullable private TwoStatePreference mSwitchPreference; @VisibleForTesting final boolean mDefaultValue; + @VisibleForTesting + final ContentObserver mContentObserver = new ContentObserver( + new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange, @Nullable Uri uri) { + updateState(mSwitchPreference); + } + }; + public MagnificationOneFingerPanningPreferenceController(Context context) { super(context, PREF_KEY); boolean defaultValue; @@ -54,10 +70,19 @@ public class MagnificationOneFingerPanningPreferenceController mDefaultValue = defaultValue; } + @Override + public void onResume() { + MagnificationCapabilities.registerObserver(mContext, mContentObserver); + } + + @Override + public void onPause() { + MagnificationCapabilities.unregisterObserver(mContext, mContentObserver); + } + @Override public int getAvailabilityStatus() { - return (Flags.enableMagnificationOneFingerPanningGesture()) - ? AVAILABLE : DISABLED_FOR_USER; + return AVAILABLE; } @Override @@ -73,14 +98,17 @@ public class MagnificationOneFingerPanningPreferenceController var toReturn = Settings.Secure.putInt(mContext.getContentResolver(), PREF_KEY, (isChecked ? ON : OFF)); - if (mSwitchPreference != null) { - refreshSummary(mSwitchPreference); - } + refreshSummary(mSwitchPreference); return toReturn; } @Override public CharSequence getSummary() { + if (!mSwitchPreference.isEnabled()) { + return mContext.getString( + R.string.accessibility_magnification_one_finger_panning_summary_unavailable); + } + return (isChecked()) ? mContext.getString( R.string.accessibility_magnification_one_finger_panning_summary_on) @@ -97,6 +125,20 @@ public class MagnificationOneFingerPanningPreferenceController public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mSwitchPreference = screen.findPreference(getPreferenceKey()); - refreshSummary(mSwitchPreference); + updateState(mSwitchPreference); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + if (preference == null) { + return; + } + @MagnificationMode int mode = + MagnificationCapabilities.getCapabilities(mContext); + preference.setEnabled( + mode == MagnificationMode.FULLSCREEN || mode == MagnificationMode.ALL); + refreshSummary(preference); } } diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java index d162272fdb6..e965a0d1cb8 100644 --- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java @@ -202,7 +202,6 @@ 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); @@ -212,6 +211,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends addPreferenceController(magnificationModePreferenceController); addFollowTypingSetting(generalCategory); + addOneFingerPanningSetting(generalCategory); addAlwaysOnSetting(generalCategory); addJoystickSetting(generalCategory); } @@ -302,6 +302,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends var oneFingerPanningPreferenceController = new MagnificationOneFingerPanningPreferenceController(getContext()); + getSettingsLifecycle().addObserver(oneFingerPanningPreferenceController); oneFingerPanningPreferenceController.displayPreference(getPreferenceScreen()); addPreferenceController(oneFingerPanningPreferenceController); } diff --git a/tests/robotests/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceControllerTest.java index 4501d273bcd..bfc8313d142 100644 --- a/tests/robotests/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/MagnificationOneFingerPanningPreferenceControllerTest.java @@ -18,19 +18,15 @@ 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.android.settings.core.BasePreferenceController.AVAILABLE; -import static com.android.settings.core.BasePreferenceController.DISABLED_FOR_USER; +import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.content.Context; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import androidx.preference.PreferenceManager; @@ -38,131 +34,137 @@ 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; +import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowContentResolver; @RunWith(RobolectricTestRunner.class) public class MagnificationOneFingerPanningPreferenceControllerTest { private static final String ONE_FINGER_PANNING_KEY = Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED; - @Rule - public final CheckFlagsRule mCheckFlagsRule = - DeviceFlagsValueProvider.createCheckFlagsRule(); - private final Context mContext = ApplicationProvider.getApplicationContext(); + private ShadowContentResolver mShadowContentResolver; private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext)); private final MagnificationOneFingerPanningPreferenceController mController = new MagnificationOneFingerPanningPreferenceController(mContext); - private PreferenceScreen mScreen; - @Before public void setUp() { + mShadowContentResolver = Shadow.extract(mContext.getContentResolver()); + final PreferenceManager preferenceManager = new PreferenceManager(mContext); - mScreen = preferenceManager.createPreferenceScreen(mContext); + final PreferenceScreen screen = 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); + screen.addPreference(mSwitchPreference); + mController.displayPreference(screen); } @Test - public void displayPreference_defaultState_correctSummarySet() { - assertThat(mSwitchPreference.getSummary()) - .isEqualTo(mContext.getString( - R.string.accessibility_magnification_one_finger_panning_summary_off)); + public void onResume_verifyRegisterCapabilityObserver() { + mController.onResume(); + assertThat(mShadowContentResolver.getContentObservers( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY))) + .hasSize(1); } @Test - @RequiresFlagsDisabled(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE) - public void getAvailabilityStatus_flagDisabled_disabled() { - int status = mController.getAvailabilityStatus(); - - assertThat(status).isEqualTo(DISABLED_FOR_USER); + public void onPause_verifyUnregisterCapabilityObserver() { + mController.onResume(); + mController.onPause(); + assertThat(mShadowContentResolver.getContentObservers( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY))) + .isEmpty(); } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE) - public void getAvailabilityStatus_featureFlagEnabled_enabled() { - int status = mController.getAvailabilityStatus(); + public void updateState_windowModeOnly_preferenceIsUnavailable() { + MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.WINDOW); + mController.updateState(mSwitchPreference); - assertThat(status).isEqualTo(AVAILABLE); + assertThat(mSwitchPreference.isEnabled()).isFalse(); + } + + @Test + public void updateState_fullscreenModeOnly_preferenceIsAvailable() { + MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.FULLSCREEN); + mController.updateState(mSwitchPreference); + + assertThat(mSwitchPreference.isEnabled()).isTrue(); + } + + @Test + public void updateState_switchMode_preferenceIsAvailable() { + MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.ALL); + mController.updateState(mSwitchPreference); + + assertThat(mSwitchPreference.isEnabled()).isTrue(); } @Test public void isChecked_defaultState_returnFalse() { + mController.updateState(mSwitchPreference); + assertThat(mController.isChecked()).isFalse(); assertThat(mSwitchPreference.isChecked()).isFalse(); } @Test - public void isChecked_settingsEnabled_returnTrue() { + public void isChecked_settingsOn_returnTrue() { Settings.Secure.putInt(mContext.getContentResolver(), ONE_FINGER_PANNING_KEY, ON); + mController.updateState(mSwitchPreference); assertThat(mController.isChecked()).isTrue(); } @Test - public void isChecked_settingsDisabled_returnTrue() { + public void isChecked_settingsOff_returnFalse() { Settings.Secure.putInt(mContext.getContentResolver(), ONE_FINGER_PANNING_KEY, OFF); + mController.updateState(mSwitchPreference); 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() { + public void getSummary_switchModeAndSettingsOff_disabledSummaryTextUsed() { + MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.ALL); Settings.Secure.putInt(mContext.getContentResolver(), ONE_FINGER_PANNING_KEY, OFF); - var summary = mController.getSummary(); + mController.updateState(mSwitchPreference); - assertThat(summary).isEqualTo(disabledSummary()); + assertThat(mController.getSummary()).isEqualTo(disabledSummary()); } @Test - public void getSummary_enable_enabledSummaryTextUsed() { + public void getSummary_switchModeAndSettingsOn_enabledSummaryTextUsed() { + MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.ALL); Settings.Secure.putInt(mContext.getContentResolver(), ONE_FINGER_PANNING_KEY, ON); - var summary = mController.getSummary(); + mController.updateState(mSwitchPreference); - assertThat(summary).isEqualTo(enabledSummary()); + assertThat(mController.getSummary()).isEqualTo(enabledSummary()); } @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE) - public void performClick_switchDefaultState_shouldReturnTrue() { + public void getSummary_windowModeOnly_unavailableSummaryTextUsed() { + MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.WINDOW); + + mController.updateState(mSwitchPreference); + + assertThat(mController.getSummary()).isEqualTo(unavailableSummary()); + } + + @Test + public void performClick_defaultSettings_toggleOn() { + MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.ALL); + mController.updateState(mSwitchPreference); + reset(mSwitchPreference); + mSwitchPreference.performClick(); verify(mSwitchPreference).setChecked(true); @@ -170,6 +172,20 @@ public class MagnificationOneFingerPanningPreferenceControllerTest { assertThat(mSwitchPreference.isChecked()).isTrue(); } + @Test + public void performClick_settingsOn_toggleOff() { + MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.ALL); + Settings.Secure.putInt(mContext.getContentResolver(), ONE_FINGER_PANNING_KEY, ON); + mController.updateState(mSwitchPreference); + reset(mSwitchPreference); + + mSwitchPreference.performClick(); + + verify(mSwitchPreference).setChecked(false); + assertThat(mController.isChecked()).isFalse(); + assertThat(mSwitchPreference.isChecked()).isFalse(); + } + private String enabledSummary() { return mContext.getString( R.string.accessibility_magnification_one_finger_panning_summary_on); @@ -179,4 +195,9 @@ public class MagnificationOneFingerPanningPreferenceControllerTest { return mContext.getString( R.string.accessibility_magnification_one_finger_panning_summary_off); } + + private String unavailableSummary() { + return mContext.getString( + R.string.accessibility_magnification_one_finger_panning_summary_unavailable); + } } diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java index cc1c72ea10e..ab2e9d1a121 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java @@ -122,6 +122,8 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { private static final String KEY_FOLLOW_TYPING = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED; + private static final String KEY_SINGLE_FINGER_PANNING = + Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED; private static final String KEY_ALWAYS_ON = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED; private static final String KEY_JOYSTICK = @@ -215,6 +217,43 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { assertThat(switchPreference.isChecked()).isFalse(); } + @Test + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE) + public void onResume_defaultStateForOneFingerPan_switchPreferenceShouldReturnFalse() { + mFragController.create(R.id.main_content, /* bundle= */ null).start().resume(); + + final TwoStatePreference switchPreference = mFragController.get().findPreference( + MagnificationOneFingerPanningPreferenceController.PREF_KEY); + assertThat(switchPreference).isNotNull(); + assertThat(switchPreference.isChecked()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE) + public void onResume_enableOneFingerPan_switchPreferenceShouldReturnTrue() { + setKeyOneFingerPanEnabled(true); + + mFragController.create(R.id.main_content, /* bundle= */ null).start().resume(); + + final TwoStatePreference switchPreference = mFragController.get().findPreference( + MagnificationOneFingerPanningPreferenceController.PREF_KEY); + assertThat(switchPreference).isNotNull(); + assertThat(switchPreference.isChecked()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE) + public void onResume_disableOneFingerPan_switchPreferenceShouldReturnFalse() { + setKeyOneFingerPanEnabled(false); + + mFragController.create(R.id.main_content, /* bundle= */ null).start().resume(); + + final TwoStatePreference switchPreference = mFragController.get().findPreference( + MagnificationOneFingerPanningPreferenceController.PREF_KEY); + assertThat(switchPreference).isNotNull(); + assertThat(switchPreference.isChecked()).isFalse(); + } + @Test public void onResume_defaultStateForAlwaysOn_switchPreferenceShouldReturnTrue() { setAlwaysOnSupported(true); @@ -777,6 +816,16 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { assertThat(mFragController.get().mSettingsPreference).isNull(); } + @Test + @DisableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE) + public void onCreateView_oneFingerPanNotSupported_settingsPreferenceIsNull() { + mFragController.create(R.id.main_content, /* bundle= */ null).start().resume(); + + final TwoStatePreference switchPreference = mFragController.get().findPreference( + MagnificationOneFingerPanningPreferenceController.PREF_KEY); + assertThat(switchPreference).isNull(); + } + @Test public void onCreateView_alwaysOnNotSupported_settingsPreferenceIsNull() { setAlwaysOnSupported(false); @@ -817,7 +866,25 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { } @Test - public void onCreateView_addTheAlwaysOnControllerToLifeCycleObserver() { + @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE) + public void onCreateView_oneFingerPanSupported_addControllerToLifeCycleObserver() { + Correspondence instanceOf = Correspondence.transforming( + observer -> (observer instanceof MagnificationOneFingerPanningPreferenceController), + "contains MagnificationOneFingerPanningPreferenceController"); + + ToggleScreenMagnificationPreferenceFragment fragment = mFragController.create( + R.id.main_content, /* bundle= */ null).start().resume().get(); + + List lifecycleObservers = ReflectionHelpers.getField( + fragment.getSettingsLifecycle(), "mObservers"); + assertThat(lifecycleObservers).isNotNull(); + assertThat(lifecycleObservers).comparingElementsUsing(instanceOf).contains(true); + } + + @Test + public void onCreateView_alwaysOnSupported_addControllerToLifeCycleObserver() { + setAlwaysOnSupported(true); + Correspondence instanceOf = Correspondence.transforming( observer -> (observer instanceof MagnificationAlwaysOnPreferenceController), "contains MagnificationAlwaysOnPreferenceController"); @@ -984,6 +1051,11 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { enabled ? ON : OFF); } + private void setKeyOneFingerPanEnabled(boolean enabled) { + Settings.Secure.putInt(mContext.getContentResolver(), KEY_SINGLE_FINGER_PANNING, + enabled ? ON : OFF); + } + private void setAlwaysOnSupported(boolean supported) { ShadowDeviceConfig.setProperty( DeviceConfig.NAMESPACE_WINDOW_MANAGER,