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
This commit is contained in:
Bill Lin
2021-04-23 15:43:17 +08:00
parent e6a20cb2ba
commit eb9b719bc5
3 changed files with 131 additions and 2 deletions

View File

@@ -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());

View File

@@ -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() {

View File

@@ -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();
}
}