Adding feature flag and replace existing boolean with settings check

Test: Locally tested + AccessibilityUserStateTest
Bug: 282039824

Change-Id: I1706629c7505e396d8a13981488bc7b52186ef2a
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index a754ba5..997f3af 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -59,6 +59,13 @@
 }
 
 flag {
+    name: "enable_magnification_one_finger_panning_gesture"
+    namespace: "accessibility"
+    description: "Whether to allow easy-mode (one finger panning gesture) for magnification"
+    bug: "282039824"
+}
+
+flag {
     name: "fix_drag_pointer_when_ending_drag"
     namespace: "accessibility"
     description: "Send the correct pointer id when transitioning from dragging to delegating states."
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index 279bd72..6d1ab9f 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -167,7 +167,7 @@
     })
     public @interface OverscrollState {}
 
-    @VisibleForTesting boolean mIsSinglePanningEnabled;
+    @VisibleForTesting final OneFingerPanningSettingsProvider mOneFingerPanningSettingsProvider;
 
     private final FullScreenMagnificationVibrationHelper mFullScreenMagnificationVibrationHelper;
 
@@ -201,7 +201,11 @@
                 displayId,
                 fullScreenMagnificationVibrationHelper,
                 /* magnificationLogger= */ null,
-                ViewConfiguration.get(context));
+                ViewConfiguration.get(context),
+                new OneFingerPanningSettingsProvider(
+                        context,
+                        Flags.enableMagnificationOneFingerPanningGesture()
+                ));
     }
 
     /** Constructor for tests. */
@@ -218,7 +222,9 @@
             int displayId,
             FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper,
             MagnificationLogger magnificationLogger,
-            ViewConfiguration viewConfiguration) {
+            ViewConfiguration viewConfiguration,
+            OneFingerPanningSettingsProvider oneFingerPanningSettingsProvider
+    ) {
         super(displayId, detectSingleFingerTripleTap, detectTwoFingerTripleTap,
                 detectShortcutTrigger, trace, callback);
         if (DEBUG_ALL) {
@@ -301,9 +307,7 @@
         mPanningScalingState = new PanningScalingState(context);
         mSinglePanningState = new SinglePanningState(context);
         mFullScreenMagnificationVibrationHelper = fullScreenMagnificationVibrationHelper;
-        setSinglePanningEnabled(
-                context.getResources()
-                        .getBoolean(R.bool.config_enable_a11y_magnification_single_panning));
+        mOneFingerPanningSettingsProvider = oneFingerPanningSettingsProvider;
         mOverscrollHandler = new OverscrollHandler();
         mIsWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
 
@@ -317,11 +321,6 @@
         transitionTo(mDetectingState);
     }
 
-    @VisibleForTesting
-    void setSinglePanningEnabled(boolean isEnabled) {
-        mIsSinglePanningEnabled = isEnabled;
-    }
-
     @Override
     void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         if (event.getActionMasked() == ACTION_DOWN) {
@@ -361,6 +360,7 @@
             Slog.i(mLogTag, "onDestroy(); delayed = "
                     + MotionEventInfo.toString(mDetectingState.mDelayedEventQueue));
         }
+        mOneFingerPanningSettingsProvider.unregister();
 
         if (mScreenStateReceiver != null) {
             mScreenStateReceiver.unregister();
@@ -524,7 +524,7 @@
                     && event.getPointerCount() == 2 // includes the pointer currently being released
                     && mPreviousState == mViewportDraggingState) {
                 // if feature flag is enabled, currently only true on watches
-                if (mIsSinglePanningEnabled) {
+                if (mOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()) {
                     mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded();
                     mOverscrollHandler.clearEdgeState();
                 }
@@ -532,7 +532,7 @@
             } else if (action == ACTION_UP || action == ACTION_CANCEL) {
                 onPanningFinished(event);
                 // if feature flag is enabled, currently only true on watches
-                if (mIsSinglePanningEnabled) {
+                if (mOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()) {
                     mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded();
                     mOverscrollHandler.clearEdgeState();
                 }
@@ -611,7 +611,7 @@
             onPan(second);
             mFullScreenMagnificationController.offsetMagnifiedRegion(mDisplayId, distanceX,
                     distanceY, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
-            if (mIsSinglePanningEnabled) {
+            if (mOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()) {
                 mOverscrollHandler.onScrollStateChanged(first, second);
             }
             return /* event consumed: */ true;
@@ -1000,7 +1000,7 @@
                                 && event.getPointerCount() == 2) {
                             transitionToViewportDraggingStateAndClear(event);
                         } else if (isActivated() && event.getPointerCount() == 2) {
-                            if (mIsSinglePanningEnabled
+                            if (mOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()
                                     && overscrollState(event, mFirstPointerDownLocation)
                                     == OVERSCROLL_VERTICAL_EDGE) {
                                 transitionToDelegatingStateAndClear();
@@ -1008,7 +1008,7 @@
                                 //Primary pointer is swiping, so transit to PanningScalingState
                                 transitToPanningScalingStateAndClear();
                             }
-                        } else if (mIsSinglePanningEnabled
+                        } else if (mOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()
                                 && isActivated()
                                 && event.getPointerCount() == 1) {
                             if (overscrollState(event, mFirstPointerDownLocation)
@@ -1255,7 +1255,7 @@
                         if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) {
                             transitionToViewportDraggingStateAndClear(event);
                         } else if (isActivated() && event.getPointerCount() == 2) {
-                            if (mIsSinglePanningEnabled
+                            if (mOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()
                                     && overscrollState(event, mFirstPointerDownLocation)
                                     == OVERSCROLL_VERTICAL_EDGE) {
                                 transitionToDelegatingStateAndClear();
@@ -1263,7 +1263,7 @@
                                 //Primary pointer is swiping, so transit to PanningScalingState
                                 transitToPanningScalingStateAndClear();
                             }
-                        } else if (mIsSinglePanningEnabled
+                        } else if (mOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()
                                 && isActivated()
                                 && event.getPointerCount() == 1) {
                             if (overscrollState(event, mFirstPointerDownLocation)
@@ -1633,7 +1633,8 @@
                 + ", mPreviousState=" + State.nameOf(mPreviousState)
                 + ", mMagnificationController=" + mFullScreenMagnificationController
                 + ", mDisplayId=" + mDisplayId
-                + ", mIsSinglePanningEnabled=" + mIsSinglePanningEnabled
+                + ", mIsSinglePanningEnabled="
+                + mOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()
                 + ", mOverscrollHandler=" + mOverscrollHandler
                 + '}';
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/OneFingerPanningSettingsProvider.java b/services/accessibility/java/com/android/server/accessibility/magnification/OneFingerPanningSettingsProvider.java
new file mode 100644
index 0000000..3cdaf98
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/OneFingerPanningSettingsProvider.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 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.server.accessibility.magnification;
+
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.Settings;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Provider for secure settings {@link Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED}.
+ */
+public class OneFingerPanningSettingsProvider {
+
+    @VisibleForTesting
+    static final String KEY = Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED;
+    private static final Uri URI = Settings.Secure.getUriFor(KEY);
+    private AtomicBoolean mCached = new AtomicBoolean();
+    @VisibleForTesting
+    ContentObserver mObserver;
+    @VisibleForTesting
+    ContentResolver mContentResolver;
+
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {
+        int OFF = 0;
+        int ON = 1;
+    }
+
+    public OneFingerPanningSettingsProvider(
+            Context context,
+            boolean featureFlagEnabled
+    ) {
+        var defaultValue = isOneFingerPanningEnabledDefault(context);
+        if (featureFlagEnabled) {
+            mContentResolver = context.getContentResolver();
+            mObserver = new ContentObserver(context.getMainThreadHandler()) {
+                @Override
+                public void onChange(boolean selfChange) {
+                    mCached.set(isOneFingerPanningEnabledInSetting(context, defaultValue));
+                }
+            };
+            mCached.set(isOneFingerPanningEnabledInSetting(context, defaultValue));
+            mContentResolver.registerContentObserver(URI, false, mObserver);
+        } else {
+            mCached.set(defaultValue);
+        }
+    }
+
+    /** Returns whether one finger panning is enabled.. */
+    public boolean isOneFingerPanningEnabled() {
+        return mCached.get();
+    }
+
+    /** Unregister content observer for listening to secure settings. */
+    public void unregister() {
+        if (mContentResolver != null) {
+            mContentResolver.unregisterContentObserver(mObserver);
+        }
+        mContentResolver = null;
+    }
+
+    private boolean isOneFingerPanningEnabledInSetting(Context context, boolean defaultValue) {
+        return State.ON == Settings.Secure.getIntForUser(
+                mContentResolver,
+                KEY,
+                (defaultValue ? State.ON : State.OFF),
+                context.getUserId());
+    }
+
+    @VisibleForTesting
+    static boolean isOneFingerPanningEnabledDefault(Context context) {
+        boolean oneFingerPanningDefaultValue;
+        try {
+            oneFingerPanningDefaultValue = context.getResources().getBoolean(
+                    com.android.internal.R.bool.config_enable_a11y_magnification_single_panning);
+        } catch (Resources.NotFoundException e) {
+            oneFingerPanningDefaultValue = false;
+        }
+        return oneFingerPanningDefaultValue;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 8c0d44c..7fbd521 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -189,6 +189,8 @@
     FullScreenMagnificationVibrationHelper mMockFullScreenMagnificationVibrationHelper;
     @Mock
     FullScreenMagnificationGestureHandler.MagnificationLogger mMockMagnificationLogger;
+    @Mock
+    OneFingerPanningSettingsProvider mMockOneFingerPanningSettingsProvider;
 
     @Rule
     public final TestableContext mContext = new TestableContext(getInstrumentation().getContext());
@@ -266,6 +268,7 @@
         mMgh.onDestroy();
         mFullScreenMagnificationController.unregister(DISPLAY_0);
         verify(mWindowMagnificationPromptController).onDestroy();
+        verify(mMockOneFingerPanningSettingsProvider).unregister();
         Settings.Secure.putFloatForUser(mContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
                 mOriginalMagnificationPersistedScale,
@@ -288,11 +291,10 @@
                         DISPLAY_0,
                         mMockFullScreenMagnificationVibrationHelper,
                         mMockMagnificationLogger,
-                        ViewConfiguration.get(mContext));
+                        ViewConfiguration.get(mContext),
+                        mMockOneFingerPanningSettingsProvider);
         if (isWatch()) {
-            h.setSinglePanningEnabled(true);
-        } else {
-            h.setSinglePanningEnabled(false);
+            enableOneFingerPanning(true);
         }
         mHandler = new TestHandler(h.mDetectingState, mClock) {
             @Override
@@ -607,8 +609,8 @@
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
     public void testTwoFingerTap_StateIsActivated_shouldInDelegating() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
-        mMgh.setSinglePanningEnabled(false);
+        assumeTrue(isWatch());
+        enableOneFingerPanning(false);
         goFromStateIdleTo(STATE_ACTIVATED);
         allowEventDelegation();
 
@@ -623,8 +625,8 @@
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
     public void testTwoFingerTap_StateIsIdle_shouldInDelegating() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
-        mMgh.setSinglePanningEnabled(false);
+        assumeTrue(isWatch());
+        enableOneFingerPanning(false);
         goFromStateIdleTo(STATE_IDLE);
         allowEventDelegation();
 
@@ -830,7 +832,7 @@
 
     @Test
     public void testActionUpNotAtEdge_singlePanningState_detectingState() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
+        assumeTrue(isWatch());
         goFromStateIdleTo(STATE_SINGLE_PANNING);
 
         send(upEvent());
@@ -841,8 +843,8 @@
 
     @Test
     public void testScroll_SinglePanningDisabled_delegatingState() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
-        mMgh.setSinglePanningEnabled(false);
+        assumeTrue(isWatch());
+        enableOneFingerPanning(false);
 
         goFromStateIdleTo(STATE_ACTIVATED);
         allowEventDelegation();
@@ -854,7 +856,7 @@
     @Test
     @FlakyTest
     public void testScroll_singleHorizontalPanningAndAtEdge_leftEdgeOverscroll() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
+        assumeTrue(isWatch());
         goFromStateIdleTo(STATE_SINGLE_PANNING);
         float centerY =
                 (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.bottom) / 2.0f;
@@ -878,7 +880,7 @@
     @Test
     @FlakyTest
     public void testScroll_singleHorizontalPanningAndAtEdge_rightEdgeOverscroll() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
+        assumeTrue(isWatch());
         goFromStateIdleTo(STATE_SINGLE_PANNING);
         float centerY =
                 (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.bottom) / 2.0f;
@@ -902,7 +904,7 @@
     @Test
     @FlakyTest
     public void testScroll_singleVerticalPanningAndAtEdge_verticalOverscroll() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
+        assumeTrue(isWatch());
         goFromStateIdleTo(STATE_SINGLE_PANNING);
         float centerX =
                 (INITIAL_MAGNIFICATION_BOUNDS.right + INITIAL_MAGNIFICATION_BOUNDS.left) / 2.0f;
@@ -924,7 +926,7 @@
 
     @Test
     public void testScroll_singlePanningAndAtEdge_noOverscroll() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
+        assumeTrue(isWatch());
         goFromStateIdleTo(STATE_SINGLE_PANNING);
         float centerY =
                 (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.bottom) / 2.0f;
@@ -946,7 +948,7 @@
 
     @Test
     public void testScroll_singleHorizontalPanningAndAtEdge_vibrate() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
+        assumeTrue(isWatch());
         goFromStateIdleTo(STATE_SINGLE_PANNING);
         mFullScreenMagnificationController.setCenter(
                 DISPLAY_0,
@@ -970,7 +972,7 @@
 
     @Test
     public void testScroll_singleVerticalPanningAndAtEdge_doNotVibrate() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
+        assumeTrue(isWatch());
         goFromStateIdleTo(STATE_SINGLE_PANNING);
         mFullScreenMagnificationController.setCenter(
                 DISPLAY_0,
@@ -993,8 +995,9 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_FULLSCREEN_FLING_GESTURE)
     public void singleFinger_testScrollAfterMagnified_startsFling() {
-        assumeTrue(mMgh.mIsSinglePanningEnabled);
+        assumeTrue(isWatch());
         goFromStateIdleTo(STATE_ACTIVATED);
 
         swipeAndHold();
@@ -1274,6 +1277,10 @@
         mFullScreenMagnificationController.reset(DISPLAY_0, /* animate= */ false);
     }
 
+    private void enableOneFingerPanning(boolean enable) {
+        when(mMockOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()).thenReturn(enable);
+    }
+
     private void assertActionsInOrder(List<MotionEvent> actualEvents,
             List<Integer> expectedActions) {
         assertTrue(actualEvents.size() == expectedActions.size());
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/OneFingerPanningSettingsProviderTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/OneFingerPanningSettingsProviderTest.java
new file mode 100644
index 0000000..ac46ef9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/OneFingerPanningSettingsProviderTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2020 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.server.accessibility.magnification;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.provider.Settings;
+import android.testing.TestableContext;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.accessibility.magnification.OneFingerPanningSettingsProvider.State;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class OneFingerPanningSettingsProviderTest {
+
+    @Rule
+    public final TestableContext mContext = new TestableContext(getInstrumentation().getContext());
+
+    private boolean mDefaultValue;
+    private boolean mOriginalIsOneFingerPanningEnabled;
+
+    private OneFingerPanningSettingsProvider mProvider;
+
+    @Before
+    public void setup() {
+        mDefaultValue = OneFingerPanningSettingsProvider.isOneFingerPanningEnabledDefault(mContext);
+        mOriginalIsOneFingerPanningEnabled = isSecureSettingsEnabled();
+    }
+
+    @After
+    public void tearDown() {
+        enableSecureSettings(mOriginalIsOneFingerPanningEnabled);
+        if (mProvider != null) {
+            mProvider.unregister();
+        }
+    }
+
+    @Test
+    public void isOneFingerPanningEnabled_flagDisabled_matchesDefault() {
+        mProvider = new OneFingerPanningSettingsProvider(mContext, /* featureFlagEnabled */ false);
+
+        assertThat(mProvider.isOneFingerPanningEnabled()).isEqualTo(mDefaultValue);
+    }
+
+    @Test
+    public void isOneFingerPanningEnabled_flagEnabledSettingEnabled_true() {
+        enableSecureSettings(true);
+        mProvider = new OneFingerPanningSettingsProvider(mContext, /* featureFlagEnabled */ true);
+
+        assertTrue(mProvider.isOneFingerPanningEnabled());
+    }
+
+    @Test
+    public void isOneFingerPanningEnabled_flagEnabledSettingDisabled_false() {
+        enableSecureSettings(false);
+        mProvider = new OneFingerPanningSettingsProvider(mContext, /* featureFlagEnabled */ true);
+
+        assertFalse(mProvider.isOneFingerPanningEnabled());
+    }
+
+    @Test
+    public void isOneFingerPanningEnabled_flagEnabledSettingsFalse_false() {
+        mProvider = new OneFingerPanningSettingsProvider(mContext, /* featureFlagEnabled */ true);
+
+        // Simulate observer triggered.
+        enableSecureSettings(false);
+        mProvider.mObserver.onChange(/* selfChange= */ false);
+
+        assertFalse(mProvider.isOneFingerPanningEnabled());
+    }
+
+    @Test
+    public void isOneFingerPanningEnabled_flagEnabledSettingsTrue_true() {
+        mProvider = new OneFingerPanningSettingsProvider(mContext, /* featureFlagEnabled */ true);
+
+        // Simulate observer triggered.
+        enableSecureSettings(true);
+        mProvider.mObserver.onChange(/* selfChange= */ false);
+
+        assertTrue(mProvider.isOneFingerPanningEnabled());
+    }
+
+    @Test
+    public void isOneFingerPanningEnabled_flagDisabledSettingsChanges_valueUnchanged() {
+        mProvider = new OneFingerPanningSettingsProvider(mContext, /* featureFlagEnabled */ false);
+        var previousValue = mProvider.isOneFingerPanningEnabled();
+
+        enableSecureSettings(!previousValue);
+
+        assertThat(mProvider.isOneFingerPanningEnabled()).isEqualTo(previousValue);
+        assertThat(mProvider.isOneFingerPanningEnabled()).isEqualTo(mDefaultValue);
+    }
+
+    @Test
+    public void unregister_featureEnabled_contentResolverNull() {
+        var provider = new OneFingerPanningSettingsProvider(
+                mContext, /* featureFlagEnabled */ true);
+
+        provider.unregister();
+
+        assertThat(provider.mContentResolver).isNull();
+    }
+
+    @Test
+    public void unregister_featureDisabled_noError() {
+        var provider = new OneFingerPanningSettingsProvider(
+                mContext, /* featureFlagEnabled */ false);
+
+        provider.unregister();
+    }
+
+    private void enableSecureSettings(boolean enable) {
+        Settings.Secure.putIntForUser(
+                mContext.getContentResolver(),
+                OneFingerPanningSettingsProvider.KEY,
+                enable ? State.ON : State.OFF,
+                mContext.getUserId());
+    }
+
+    private boolean isSecureSettingsEnabled() {
+        return State.ON == Settings.Secure.getIntForUser(
+                mContext.getContentResolver(),
+                OneFingerPanningSettingsProvider.KEY,
+                mDefaultValue ? State.ON : State.OFF,
+                mContext.getUserId());
+    }
+}