1/ Add OneHandedState to manage the transition flow
1) Define STATEs flags for OHM CUJ:
STATE_NONE (0)
STATE_ENTERING (1)
STATE_ACTIVE (2)
STATE_EXITING (3)
STATE_NONE->STATE_ENTERING->STATE_ACTIVE->STATE_EXITING
- Default = STATE_NONE
- When user trigger OHM = STATE_ENTERING
- When user is in OHM = STATE_ACTIVE
- When user exit OHM = STATE_EXITING
- When user finish exiting OHM = STATE_NONE
2) Unbound one handed mode state from OHMDAOrganzier
- Move isInOneHandedMode() to OneHandedState
Test: atest OneHandedStateTest
Test: atest WMShellUnitTests
Test: manual test
Bug: 185558765
Change-Id: Ida2f23da6c4df9cbcf6903ffc9ad07fcfc73bbcb
This commit is contained in:
@@ -21,6 +21,10 @@ import static android.os.UserHandle.myUserId;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
|
||||
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 android.annotation.BinderThread;
|
||||
import android.content.ComponentName;
|
||||
@@ -62,8 +66,7 @@ import java.io.PrintWriter;
|
||||
/**
|
||||
* Manages and manipulates the one handed states, transitions, and gesture for phones.
|
||||
*/
|
||||
public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
OneHandedTransitionCallback {
|
||||
public class OneHandedController implements RemoteCallable<OneHandedController> {
|
||||
private static final String TAG = "OneHandedController";
|
||||
|
||||
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
|
||||
@@ -75,7 +78,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
|
||||
private volatile boolean mIsOneHandedEnabled;
|
||||
private volatile boolean mIsSwipeToNotificationEnabled;
|
||||
private volatile boolean mIsTransitioning;
|
||||
private boolean mTaskChangeToExit;
|
||||
private boolean mLockedDisabled;
|
||||
private int mUserId;
|
||||
@@ -89,6 +91,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
private final OneHandedAccessibilityUtil mOneHandedAccessibilityUtil;
|
||||
private final OneHandedTimeoutHandler mTimeoutHandler;
|
||||
private final OneHandedTouchHandler mTouchHandler;
|
||||
private final OneHandedState mState;
|
||||
private final OneHandedTutorialHandler mTutorialHandler;
|
||||
private final OneHandedUiEventLogger mOneHandedUiEventLogger;
|
||||
private final TaskStackListenerImpl mTaskStackListener;
|
||||
@@ -162,6 +165,19 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
}
|
||||
};
|
||||
|
||||
private final OneHandedTransitionCallback mTransitionCallBack =
|
||||
new OneHandedTransitionCallback() {
|
||||
@Override
|
||||
public void onStartFinished(Rect bounds) {
|
||||
mState.setState(STATE_ACTIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopFinished(Rect bounds) {
|
||||
mState.setState(STATE_NONE);
|
||||
}
|
||||
};
|
||||
|
||||
private final TaskStackListenerCallback mTaskStackListenerCallback =
|
||||
new TaskStackListenerCallback() {
|
||||
@Override
|
||||
@@ -200,6 +216,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil();
|
||||
OneHandedAccessibilityUtil accessibilityUtil = new OneHandedAccessibilityUtil(context);
|
||||
OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor);
|
||||
OneHandedState transitionState = new OneHandedState();
|
||||
OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context,
|
||||
windowManager, mainExecutor);
|
||||
OneHandedAnimationController animationController =
|
||||
@@ -218,7 +235,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
ServiceManager.getService(Context.OVERLAY_SERVICE));
|
||||
return new OneHandedController(context, displayController,
|
||||
oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler,
|
||||
gestureHandler, settingsUtil, accessibilityUtil, timeoutHandler,
|
||||
gestureHandler, settingsUtil, accessibilityUtil, timeoutHandler, transitionState,
|
||||
oneHandedUiEventsLogger, overlayManager, taskStackListener, mainExecutor,
|
||||
mainHandler);
|
||||
}
|
||||
@@ -234,6 +251,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
OneHandedSettingsUtil settingsUtil,
|
||||
OneHandedAccessibilityUtil oneHandedAccessibilityUtil,
|
||||
OneHandedTimeoutHandler timeoutHandler,
|
||||
OneHandedState state,
|
||||
OneHandedUiEventLogger uiEventsLogger,
|
||||
IOverlayManager overlayManager,
|
||||
TaskStackListenerImpl taskStackListener,
|
||||
@@ -246,6 +264,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
mDisplayAreaOrganizer = displayAreaOrganizer;
|
||||
mDisplayController = displayController;
|
||||
mTouchHandler = touchHandler;
|
||||
mState = state;
|
||||
mTutorialHandler = tutorialHandler;
|
||||
mGestureHandler = gestureHandler;
|
||||
mOverlayManager = overlayManager;
|
||||
@@ -330,26 +349,27 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
|
||||
@VisibleForTesting
|
||||
void startOneHanded() {
|
||||
if (isLockedDisabled() || mIsTransitioning) {
|
||||
if (isLockedDisabled()) {
|
||||
Slog.d(TAG, "Temporary lock disabled");
|
||||
return;
|
||||
}
|
||||
if (mState.isTransitioning() || mState.isInOneHanded()) {
|
||||
return;
|
||||
}
|
||||
final int currentRotation = mDisplayAreaOrganizer.getDisplayLayout().rotation();
|
||||
if (currentRotation != Surface.ROTATION_0 && currentRotation != Surface.ROTATION_180) {
|
||||
Slog.w(TAG, "One handed mode only support portrait mode");
|
||||
return;
|
||||
}
|
||||
if (!mDisplayAreaOrganizer.isInOneHanded()) {
|
||||
mIsTransitioning = true;
|
||||
final int yOffSet = Math.round(
|
||||
mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction);
|
||||
mOneHandedAccessibilityUtil.announcementForScreenReader(
|
||||
mOneHandedAccessibilityUtil.getOneHandedStartDescription());
|
||||
mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);
|
||||
mTimeoutHandler.resetTimer();
|
||||
mOneHandedUiEventLogger.writeEvent(
|
||||
OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN);
|
||||
}
|
||||
mState.setState(STATE_ENTERING);
|
||||
final int yOffSet = Math.round(
|
||||
mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction);
|
||||
mOneHandedAccessibilityUtil.announcementForScreenReader(
|
||||
mOneHandedAccessibilityUtil.getOneHandedStartDescription());
|
||||
mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);
|
||||
mTimeoutHandler.resetTimer();
|
||||
mOneHandedUiEventLogger.writeEvent(
|
||||
OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -358,14 +378,15 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
}
|
||||
|
||||
private void stopOneHanded(int uiEvent) {
|
||||
if (mDisplayAreaOrganizer.isInOneHanded() && !mIsTransitioning) {
|
||||
mIsTransitioning = true;
|
||||
mOneHandedAccessibilityUtil.announcementForScreenReader(
|
||||
mOneHandedAccessibilityUtil.getOneHandedStopDescription());
|
||||
mDisplayAreaOrganizer.scheduleOffset(0, 0);
|
||||
mTimeoutHandler.removeTimer();
|
||||
mOneHandedUiEventLogger.writeEvent(uiEvent);
|
||||
if (mState.isTransitioning() || mState.getState() == STATE_NONE) {
|
||||
return;
|
||||
}
|
||||
mState.setState(STATE_EXITING);
|
||||
mOneHandedAccessibilityUtil.announcementForScreenReader(
|
||||
mOneHandedAccessibilityUtil.getOneHandedStopDescription());
|
||||
mDisplayAreaOrganizer.scheduleOffset(0, 0);
|
||||
mTimeoutHandler.removeTimer();
|
||||
mOneHandedUiEventLogger.writeEvent(uiEvent);
|
||||
}
|
||||
|
||||
private void setThreeButtonModeEnabled(boolean enabled) {
|
||||
@@ -388,7 +409,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(mGestureHandler);
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler);
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(mBackgroundPanelOrganizer);
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(this);
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(mTransitionCallBack);
|
||||
if (mTaskChangeToExit) {
|
||||
mTaskStackListener.addListener(mTaskStackListenerCallback);
|
||||
}
|
||||
@@ -523,8 +544,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
}
|
||||
|
||||
private void updateOneHandedEnabled() {
|
||||
if (mDisplayAreaOrganizer.isInOneHanded()) {
|
||||
stopOneHanded();
|
||||
if (mState.getState() == STATE_ENTERING || mState.getState() == STATE_ACTIVE) {
|
||||
mMainExecutor.execute(() -> stopOneHanded());
|
||||
}
|
||||
|
||||
mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled);
|
||||
@@ -615,8 +636,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
pw.println(mLockedDisabled);
|
||||
pw.print(innerPrefix + "mUserId=");
|
||||
pw.println(mUserId);
|
||||
pw.print(innerPrefix + "mIsTransitioning=");
|
||||
pw.println(mIsTransitioning);
|
||||
|
||||
if (mBackgroundPanelOrganizer != null) {
|
||||
mBackgroundPanelOrganizer.dump(pw);
|
||||
@@ -638,6 +657,10 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
mTimeoutHandler.dump(pw);
|
||||
}
|
||||
|
||||
if (mState != null) {
|
||||
mState.dump(pw);
|
||||
}
|
||||
|
||||
if (mTutorialHandler != null) {
|
||||
mTutorialHandler.dump(pw);
|
||||
}
|
||||
@@ -662,26 +685,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(b/185558765) To implement a state machine for One-Handed transition state machine.
|
||||
* ONE_HANDDE_STATE_TRANSITION {
|
||||
* STATE_DEFAULT,
|
||||
* STATE_TRANSITIONING,
|
||||
* STATE_ENTER_ONE_HANED,
|
||||
* STATE_EXIT_ONE_HANDED
|
||||
* }
|
||||
* and we need to align the state to launcher3 quick steps through SysuiProxy.
|
||||
*/
|
||||
@Override
|
||||
public void onStartFinished(Rect bounds) {
|
||||
mIsTransitioning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopFinished(Rect bounds) {
|
||||
mIsTransitioning = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface for calls from outside the Shell, within the host process.
|
||||
*/
|
||||
|
||||
@@ -65,6 +65,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
|
||||
private final Rect mDefaultDisplayBounds = new Rect();
|
||||
private final OneHandedSettingsUtil mOneHandedSettingsUtil;
|
||||
|
||||
// TODO(b/185558765) Remove after OneHandedTransitionState.java merged
|
||||
private boolean mIsInOneHanded;
|
||||
private int mEnterExitAnimationDurationMs;
|
||||
|
||||
@@ -262,6 +263,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
|
||||
@OneHandedAnimationController.TransitionDirection int direction) {
|
||||
// Only finishOffset() can update mIsInOneHanded to ensure the state is handle in sequence,
|
||||
// the flag *MUST* be updated before dispatch mTransitionCallbacks
|
||||
// TODO(b/185558765) Remove after OneHandedTransitionState.java merged
|
||||
mIsInOneHanded = (offset > 0 || direction == TRANSITION_DIRECTION_TRIGGER);
|
||||
mLastVisualDisplayBounds.offsetTo(0,
|
||||
direction == TRANSITION_DIRECTION_TRIGGER ? offset : 0);
|
||||
@@ -276,6 +278,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(b/185558765) Remove after OneHandedTransitionState.java merged
|
||||
* The latest state of one handed mode
|
||||
*
|
||||
* @return true Currently is in one handed mode, otherwise is not in one handed mode
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.wm.shell.onehanded;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
Represents current OHM state by following steps, a generic CUJ is
|
||||
STATE_NONE -> STATE_ENTERING -> STATE_ACTIVE -> STATE_EXITING -> STATE_NONE
|
||||
*/
|
||||
public class OneHandedState {
|
||||
/** DEFAULT STATE after OHM feature initialized. */
|
||||
public static final int STATE_NONE = 0x00000000;
|
||||
/** The state flag set when user trigger OHM. */
|
||||
public static final int STATE_ENTERING = 0x00000001;
|
||||
/** The state flag set when transitioning */
|
||||
public static final int STATE_ACTIVE = 0x00000002;
|
||||
/** The state flag set when user stop OHM feature. */
|
||||
public static final int STATE_EXITING = 0x00000004;
|
||||
|
||||
@IntDef(prefix = { "STATE_" }, value = {
|
||||
STATE_NONE,
|
||||
STATE_ENTERING,
|
||||
STATE_ACTIVE,
|
||||
STATE_EXITING
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface State {}
|
||||
|
||||
public OneHandedState() {
|
||||
sCurrentState = STATE_NONE;
|
||||
}
|
||||
|
||||
@State
|
||||
private static int sCurrentState = STATE_NONE;
|
||||
|
||||
private static final String TAG = OneHandedState.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* Gets current transition state of One handed mode.
|
||||
*
|
||||
* @return The bitwise flags representing current states.
|
||||
*/
|
||||
public @State int getState() {
|
||||
return sCurrentState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the One handed mode is in transitioning state.
|
||||
* @return true if One handed mode is in transitioning states.
|
||||
*/
|
||||
public boolean isTransitioning() {
|
||||
return sCurrentState == STATE_ENTERING || sCurrentState == STATE_EXITING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the One handed mode active state.
|
||||
* @return true if One handed mode is active state.
|
||||
*/
|
||||
public boolean isInOneHanded() {
|
||||
return sCurrentState == STATE_ACTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets new state for One handed mode feature.
|
||||
* @param newState The bitwise value to represent current transition states.
|
||||
*/
|
||||
public void setState(@State int newState) {
|
||||
sCurrentState = newState;
|
||||
}
|
||||
|
||||
/** Dumps internal state. */
|
||||
public void dump(PrintWriter pw) {
|
||||
final String innerPrefix = " ";
|
||||
pw.println(TAG + "states: ");
|
||||
pw.println(innerPrefix + "sCurrentState=" + sCurrentState);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.wm.shell.onehanded;
|
||||
|
||||
import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING;
|
||||
import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -61,6 +64,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
OneHandedAccessibilityUtil mOneHandedAccessibilityUtil;
|
||||
OneHandedController mSpiedOneHandedController;
|
||||
OneHandedTimeoutHandler mSpiedTimeoutHandler;
|
||||
OneHandedState mSpiedTransitionState;
|
||||
|
||||
@Mock
|
||||
DisplayController mMockDisplayController;
|
||||
@@ -99,9 +103,9 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
mDisplay = mContext.getDisplay();
|
||||
mDisplayLayout = new DisplayLayout(mContext, mDisplay);
|
||||
mSpiedTimeoutHandler = spy(new OneHandedTimeoutHandler(mMockShellMainExecutor));
|
||||
mSpiedTransitionState = spy(new OneHandedState());
|
||||
|
||||
when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
|
||||
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
|
||||
when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
|
||||
when(mMockBackgroundOrganizer.getBackgroundSurface()).thenReturn(mMockLeash);
|
||||
when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(
|
||||
@@ -129,6 +133,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
mMockSettingsUitl,
|
||||
mOneHandedAccessibilityUtil,
|
||||
mSpiedTimeoutHandler,
|
||||
mSpiedTransitionState,
|
||||
mMockUiEventLogger,
|
||||
mMockOverlayManager,
|
||||
mMockTaskStackListener,
|
||||
@@ -139,18 +144,13 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
|
||||
@Test
|
||||
public void testDefaultShouldNotInOneHanded() {
|
||||
final OneHandedAnimationController animationController = new OneHandedAnimationController(
|
||||
mContext);
|
||||
OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer(
|
||||
mContext, mDisplayLayout, mMockSettingsUitl, animationController,
|
||||
mMockTutorialHandler, mMockBackgroundOrganizer, mMockShellMainExecutor);
|
||||
|
||||
assertThat(displayAreaOrganizer.isInOneHanded()).isFalse();
|
||||
// Assert default transition state is STATE_NONE
|
||||
assertThat(mSpiedTransitionState.getState()).isEqualTo(STATE_NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartOneHandedShouldTriggerScheduleOffset() {
|
||||
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
|
||||
mSpiedTransitionState.setState(STATE_NONE);
|
||||
mSpiedOneHandedController.setOneHandedEnabled(true);
|
||||
mSpiedOneHandedController.startOneHanded();
|
||||
|
||||
@@ -160,7 +160,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
@Test
|
||||
public void testStartOneHandedShouldNotTriggerScheduleOffset() {
|
||||
mSpiedOneHandedController.setOneHandedEnabled(true);
|
||||
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(true);
|
||||
mSpiedTransitionState.setState(STATE_ENTERING);
|
||||
mSpiedOneHandedController.startOneHanded();
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt());
|
||||
@@ -168,7 +168,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
|
||||
@Test
|
||||
public void testStopOneHanded() {
|
||||
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
|
||||
mSpiedTransitionState.setState(STATE_NONE);
|
||||
mSpiedOneHandedController.stopOneHanded();
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt());
|
||||
@@ -192,7 +192,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
|
||||
@Test
|
||||
public void testStopOneHandedShouldRemoveTimer() {
|
||||
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(true);
|
||||
mSpiedTransitionState.setState(STATE_ENTERING);
|
||||
mSpiedOneHandedController.stopOneHanded();
|
||||
|
||||
verify(mSpiedTimeoutHandler, atLeastOnce()).removeTimer();
|
||||
@@ -280,7 +280,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
|
||||
@Test
|
||||
public void testKeyguardShowingLockOneHandedDisabled() {
|
||||
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
|
||||
mSpiedTransitionState.setState(STATE_NONE);
|
||||
mSpiedOneHandedController.setOneHandedEnabled(true);
|
||||
mSpiedOneHandedController.setLockedDisabled(true /* locked */, false /* enabled */);
|
||||
mSpiedOneHandedController.startOneHanded();
|
||||
@@ -290,7 +290,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
|
||||
@Test
|
||||
public void testResetKeyguardShowingLockOneHandedDisabled() {
|
||||
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
|
||||
mSpiedTransitionState.setState(STATE_NONE);
|
||||
mSpiedOneHandedController.setOneHandedEnabled(true);
|
||||
mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */);
|
||||
mSpiedOneHandedController.startOneHanded();
|
||||
@@ -302,7 +302,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
public void testRotation90CanNotStartOneHanded() {
|
||||
final DisplayLayout landscapeDisplayLayout = new DisplayLayout(mDisplayLayout);
|
||||
landscapeDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90);
|
||||
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
|
||||
mSpiedTransitionState.setState(STATE_NONE);
|
||||
when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(landscapeDisplayLayout);
|
||||
mSpiedOneHandedController.setOneHandedEnabled(true);
|
||||
mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */);
|
||||
@@ -315,7 +315,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
public void testRotation180CanStartOneHanded() {
|
||||
final DisplayLayout testDisplayLayout = new DisplayLayout(mDisplayLayout);
|
||||
testDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_180);
|
||||
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
|
||||
mSpiedTransitionState.setState(STATE_NONE);
|
||||
when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(testDisplayLayout);
|
||||
mSpiedOneHandedController.setOneHandedEnabled(true);
|
||||
mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */);
|
||||
@@ -328,7 +328,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
public void testRotation270CanNotStartOneHanded() {
|
||||
final DisplayLayout testDisplayLayout = new DisplayLayout(mDisplayLayout);
|
||||
testDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270);
|
||||
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
|
||||
mSpiedTransitionState.setState(STATE_NONE);
|
||||
when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(testDisplayLayout);
|
||||
mSpiedOneHandedController.setOneHandedEnabled(true);
|
||||
mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */);
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* 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.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.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.om.IOverlayManager;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.util.ArrayMap;
|
||||
import android.view.Display;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class OneHandedStateTest extends OneHandedTestCase {
|
||||
private int mCurrentUser = UserHandle.myUserId();
|
||||
|
||||
Display mDisplay;
|
||||
DisplayLayout mDisplayLayout;
|
||||
OneHandedAccessibilityUtil mOneHandedAccessibilityUtil;
|
||||
OneHandedController mSpiedOneHandedController;
|
||||
OneHandedTimeoutHandler mSpiedTimeoutHandler;
|
||||
OneHandedState mSpiedState;
|
||||
|
||||
@Mock
|
||||
DisplayController mMockDisplayController;
|
||||
@Mock
|
||||
OneHandedBackgroundPanelOrganizer mMockBackgroundOrganizer;
|
||||
@Mock
|
||||
OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
|
||||
@Mock
|
||||
OneHandedTouchHandler mMockTouchHandler;
|
||||
@Mock
|
||||
OneHandedTutorialHandler mMockTutorialHandler;
|
||||
@Mock
|
||||
OneHandedGestureHandler mMockGestureHandler;
|
||||
@Mock
|
||||
OneHandedSettingsUtil mMockSettingsUitl;
|
||||
@Mock
|
||||
OneHandedUiEventLogger mMockUiEventLogger;
|
||||
@Mock
|
||||
IOverlayManager mMockOverlayManager;
|
||||
@Mock
|
||||
TaskStackListenerImpl mMockTaskStackListener;
|
||||
@Mock
|
||||
ShellExecutor mMockShellMainExecutor;
|
||||
@Mock
|
||||
SurfaceControl mMockLeash;
|
||||
@Mock
|
||||
Handler mMockShellMainHandler;
|
||||
|
||||
final boolean mDefaultEnabled = true;
|
||||
final boolean mDefaultSwipeToNotificationEnabled = false;
|
||||
final boolean mDefaultTapAppToExitEnabled = true;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mDisplay = mContext.getDisplay();
|
||||
mDisplayLayout = new DisplayLayout(mContext, mDisplay);
|
||||
mSpiedTimeoutHandler = spy(new OneHandedTimeoutHandler(mMockShellMainExecutor));
|
||||
mSpiedState = spy(new OneHandedState());
|
||||
|
||||
when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
|
||||
when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
|
||||
when(mMockBackgroundOrganizer.getBackgroundSurface()).thenReturn(mMockLeash);
|
||||
when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(
|
||||
mDefaultEnabled);
|
||||
when(mMockSettingsUitl.getSettingsOneHandedModeTimeout(any(), anyInt())).thenReturn(
|
||||
OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS);
|
||||
when(mMockSettingsUitl.getSettingsTapsAppToExit(any(), anyInt())).thenReturn(
|
||||
mDefaultTapAppToExitEnabled);
|
||||
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
|
||||
mDefaultSwipeToNotificationEnabled);
|
||||
|
||||
when(mMockDisplayAreaOrganizer.getLastDisplayBounds()).thenReturn(
|
||||
new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height()));
|
||||
when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(mDisplayLayout);
|
||||
|
||||
mOneHandedAccessibilityUtil = new OneHandedAccessibilityUtil(mContext);
|
||||
mSpiedOneHandedController = spy(new OneHandedController(
|
||||
mContext,
|
||||
mMockDisplayController,
|
||||
mMockBackgroundOrganizer,
|
||||
mMockDisplayAreaOrganizer,
|
||||
mMockTouchHandler,
|
||||
mMockTutorialHandler,
|
||||
mMockGestureHandler,
|
||||
mMockSettingsUitl,
|
||||
mOneHandedAccessibilityUtil,
|
||||
mSpiedTimeoutHandler,
|
||||
mSpiedState,
|
||||
mMockUiEventLogger,
|
||||
mMockOverlayManager,
|
||||
mMockTaskStackListener,
|
||||
mMockShellMainExecutor,
|
||||
mMockShellMainHandler)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testState_stateEntering_isTransitioning() {
|
||||
mSpiedState.setState(STATE_ENTERING);
|
||||
|
||||
assertThat(mSpiedState.isTransitioning()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testState_stateExiting_isTransitioning() {
|
||||
mSpiedState.setState(STATE_EXITING);
|
||||
|
||||
assertThat(mSpiedState.isTransitioning()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInEnteringState_shouldSkipDupTrigger() {
|
||||
when(mSpiedState.getState()).thenReturn(STATE_ENTERING);
|
||||
when(mSpiedState.isTransitioning()).thenReturn(true);
|
||||
when(mSpiedState.isInOneHanded()).thenReturn(false);
|
||||
mSpiedOneHandedController.startOneHanded();
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInActiveState_shouldSkipDupTrigger() {
|
||||
when(mSpiedState.getState()).thenReturn(STATE_ACTIVE);
|
||||
when(mSpiedState.isTransitioning()).thenReturn(false);
|
||||
when(mSpiedState.isInOneHanded()).thenReturn(true);
|
||||
mSpiedOneHandedController.startOneHanded();
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInActiveState_canExit() {
|
||||
when(mSpiedState.getState()).thenReturn(STATE_ACTIVE);
|
||||
when(mSpiedState.isTransitioning()).thenReturn(false);
|
||||
mSpiedOneHandedController.stopOneHanded();
|
||||
|
||||
verify(mSpiedState).setState(STATE_EXITING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInEnteringState_shouldSkipExitAction() {
|
||||
when(mSpiedState.getState()).thenReturn(STATE_ENTERING);
|
||||
when(mSpiedState.isTransitioning()).thenReturn(true);
|
||||
mSpiedOneHandedController.stopOneHanded();
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInExitingState_shouldSkipStartAction() {
|
||||
when(mSpiedState.getState()).thenReturn(STATE_EXITING);
|
||||
when(mSpiedState.isTransitioning()).thenReturn(true);
|
||||
mSpiedOneHandedController.startOneHanded();
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInExitingState_shouldSkipStopAction() {
|
||||
when(mSpiedState.getState()).thenReturn(STATE_EXITING);
|
||||
when(mSpiedState.isTransitioning()).thenReturn(true);
|
||||
mSpiedOneHandedController.stopOneHanded();
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInActiveState_disableOHM_shouldStopOHM() {
|
||||
when(mSpiedState.getState()).thenReturn(STATE_ACTIVE);
|
||||
when(mSpiedState.isTransitioning()).thenReturn(false);
|
||||
when(mSpiedState.isInOneHanded()).thenReturn(true);
|
||||
mSpiedOneHandedController.setOneHandedEnabled(false);
|
||||
|
||||
verify(mMockShellMainExecutor).execute(any());
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import org.mockito.MockitoAnnotations;
|
||||
public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
|
||||
OneHandedTimeoutHandler mTimeoutHandler;
|
||||
OneHandedController mOneHandedController;
|
||||
OneHandedState mSpiedTransitionState;
|
||||
|
||||
@Mock
|
||||
OneHandedGestureHandler mMockGestureHandler;
|
||||
@@ -73,6 +74,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mTimeoutHandler = new OneHandedTimeoutHandler(mMockShellMainExecutor);
|
||||
mSpiedTransitionState = new OneHandedState();
|
||||
|
||||
when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
|
||||
mOneHandedController = new OneHandedController(
|
||||
@@ -86,6 +88,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
|
||||
mMockSettingsUtil,
|
||||
mMockAccessibilityUtil,
|
||||
mTimeoutHandler,
|
||||
mSpiedTransitionState,
|
||||
mMockUiEventLogger,
|
||||
mMockOverlayManager,
|
||||
mMockTaskStackListener,
|
||||
|
||||
Reference in New Issue
Block a user