Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb9b719b authored by Bill Lin's avatar Bill Lin
Browse files

3/ Listen ONE_HANDED_MODE_ACTIVATED for A11y shortcut action

- Observe ONE_HANDED_MODE_ACTIVATED secure settings key
- Skip action when OneHandedState is in transition
  1. STATE_ENTERING
  2. STATE_EXITING
- Skip action if current OneHandedState = request activate
  1. STATE NONE -> Shortcut request ACTIVATED : StartOneHanded
  2. STATE_ACTIVE -> Shortcut request non ACTIVATED : StopOneHanded
  3. STATE_NONE -> Shortcut request non ACTIVATED : SKip
  4. STATE_ACTIVE -> Shortcut request ACTIVATED : Skip
- Controller will update latest state to secure setting
  ONE_HANDED_MODE_ACTIVATED either trigger by gesture or shortcut

Test: atest WMShellUnitTests
Test: enable shortcut and click
Bug: 182425480
Change-Id: I03bd2679a5a08801efc9868148adfddef87171f4
parent e6a20cb2
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
                }
            };

    private final ContentObserver mActivatedObserver;
    private final ContentObserver mEnabledObserver;
    private final ContentObserver mTimeoutObserver;
    private final ContentObserver mTaskChangeExitObserver;
@@ -170,11 +171,13 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
                @Override
                public void onStartFinished(Rect bounds) {
                    mState.setState(STATE_ACTIVE);
                    notifyShortcutState(STATE_ACTIVE);
                }

                @Override
                public void onStopFinished(Rect bounds) {
                    mState.setState(STATE_NONE);
                    notifyShortcutState(STATE_NONE);
                }
            };

@@ -287,6 +290,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
                        context.getContentResolver(), mUserId);
        mTimeoutHandler = timeoutHandler;

        mActivatedObserver = getObserver(this::onActivatedActionChanged);
        mEnabledObserver = getObserver(this::onEnabledSettingChanged);
        mTimeoutObserver = getObserver(this::onTimeoutSettingChanged);
        mTaskChangeExitObserver = getObserver(this::onTaskChangeExitSettingChanged);
@@ -347,6 +351,12 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        updateOneHandedEnabled();
    }

    @VisibleForTesting
    void notifyShortcutState(@OneHandedState.State int state) {
        mOneHandedSettingsUtil.setOneHandedModeActivated(
                mContext.getContentResolver(), state == STATE_ACTIVE ? 1 : 0, mUserId);
    }

    @VisibleForTesting
    void startOneHanded() {
        if (isLockedDisabled()) {
@@ -416,6 +426,9 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
    }

    private void registerSettingObservers(int newUserId) {
        mOneHandedSettingsUtil.registerSettingsKeyObserver(
                Settings.Secure.ONE_HANDED_MODE_ACTIVATED,
                mContext.getContentResolver(), mActivatedObserver, newUserId);
        mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED,
                mContext.getContentResolver(), mEnabledObserver, newUserId);
        mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT,
@@ -465,6 +478,26 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        };
    }

    @VisibleForTesting
    void onActivatedActionChanged() {
        if (mState.isTransitioning() || !isOneHandedEnabled()) {
            return;
        }

        final boolean isActivated = mState.getState() == STATE_ACTIVE;
        final boolean requestActivated = mOneHandedSettingsUtil.getOneHandedModeActivated(
                mContext.getContentResolver(), mUserId);
        // When gesture trigger action, we will update settings and introduce observer callback
        // again, then the following logic will just ignore the second redundant callback.
        if (isActivated ^ requestActivated) {
            if (requestActivated) {
                startOneHanded();
            } else {
                stopOneHanded();
            }
        }
    }

    @VisibleForTesting
    void onEnabledSettingChanged() {
        final boolean enabled = mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
@@ -544,6 +577,11 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        return mLockedDisabled;
    }

    @VisibleForTesting
    boolean isOneHandedEnabled() {
        return mIsOneHandedEnabled;
    }

    private void updateOneHandedEnabled() {
        if (mState.getState() == STATE_ENTERING || mState.getState() == STATE_ACTIVE) {
            mMainExecutor.execute(() -> stopOneHanded());
+24 −2
Original line number Diff line number Diff line
@@ -131,8 +131,28 @@ public final class OneHandedSettingsUtil {
     * Returns whether swipe bottom to notification gesture enabled or not.
     */
    public boolean getSettingsSwipeToNotificationEnabled(ContentResolver resolver, int userId) {
        return Settings.Secure.getInt(resolver,
                Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 0 /* Default OFF */) == 1;
        return Settings.Secure.getIntForUser(resolver,
                Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 0, userId) == 1;
    }

    /**
     * Sets one handed activated or not to notify state for shortcut
     *
     * @return activated or not
     */
    public boolean getOneHandedModeActivated(ContentResolver resolver, int userId) {
        return Settings.Secure.getIntForUser(resolver,
                Settings.Secure.ONE_HANDED_MODE_ACTIVATED, 0, userId) == 1;
    }

    /**
     * Sets one handed activated or not to notify state for shortcut
     *
     * @return activated or not
     */
    public boolean setOneHandedModeActivated(ContentResolver resolver, int state, int userId) {
        return Settings.Secure.putIntForUser(resolver,
                Settings.Secure.ONE_HANDED_MODE_ACTIVATED, state, userId);
    }

    void dump(PrintWriter pw, String prefix, ContentResolver resolver,
@@ -145,6 +165,8 @@ public final class OneHandedSettingsUtil {
        pw.println(getSettingsOneHandedModeTimeout(resolver, userId));
        pw.print(innerPrefix + "tapsAppToExit=");
        pw.println(getSettingsTapsAppToExit(resolver, userId));
        pw.print(innerPrefix + "shortcutActivated=");
        pw.println(getOneHandedModeActivated(resolver, userId));
    }

    public OneHandedSettingsUtil() {
+69 −0
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@

package com.android.wm.shell.onehanded;

import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING;
import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING;
import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;

import static com.google.common.truth.Truth.assertThat;
@@ -360,4 +362,71 @@ public class OneHandedControllerTest extends OneHandedTestCase {

        verify(mMockGestureHandler).onGestureEnabled(isOneHandedEnabled);
    }

    @Test
    public void testStateActive_shortcutRequestActivate_skipActions() {
        when(mSpiedTransitionState.getState()).thenReturn(STATE_ACTIVE);
        when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
        when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
        mSpiedOneHandedController.onActivatedActionChanged();

        verify(mSpiedOneHandedController, never()).startOneHanded();
        verify(mSpiedOneHandedController, never()).stopOneHanded();
    }

    @Test
    public void testStateNotActive_shortcutRequestInActivate_skipAction() {
        when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
        when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
        when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(false);
        mSpiedOneHandedController.onActivatedActionChanged();

        verify(mSpiedOneHandedController, never()).startOneHanded();
        verify(mSpiedOneHandedController, never()).stopOneHanded();
    }

    @Test
    public void testStateNotActive_shortcutRequestActivate_doAction() {
        when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
        when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
        when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
        mSpiedOneHandedController.onActivatedActionChanged();

        verify(mSpiedOneHandedController).startOneHanded();
        verify(mSpiedOneHandedController, never()).stopOneHanded();
    }

    @Test
    public void testEnteringTransition_shortcutRequestActivate_skipActions() {
        when(mSpiedTransitionState.getState()).thenReturn(STATE_ENTERING);
        when(mSpiedTransitionState.isTransitioning()).thenReturn(true);
        when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
        mSpiedOneHandedController.onActivatedActionChanged();

        verify(mSpiedOneHandedController, never()).startOneHanded();
        verify(mSpiedOneHandedController, never()).stopOneHanded();
    }

    @Test
    public void testExitingTransition_shortcutRequestActivate_skipActions() {
        when(mSpiedTransitionState.getState()).thenReturn(STATE_EXITING);
        when(mSpiedTransitionState.isTransitioning()).thenReturn(true);
        when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
        mSpiedOneHandedController.onActivatedActionChanged();

        verify(mSpiedOneHandedController, never()).startOneHanded();
        verify(mSpiedOneHandedController, never()).stopOneHanded();
    }

    @Test
    public void testOneHandedDisabled_shortcutEnabled_skipActions() {
        when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false);
        when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
        when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
        when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
        mSpiedOneHandedController.onActivatedActionChanged();

        verify(mSpiedOneHandedController, never()).startOneHanded();
        verify(mSpiedOneHandedController, never()).stopOneHanded();
    }
}