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:
Bill Lin
2021-04-19 14:10:03 +08:00
parent 1027fb5c21
commit 8a8f117280
6 changed files with 391 additions and 65 deletions

View File

@@ -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.
*/

View File

@@ -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

View File

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

View File

@@ -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 */);

View File

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

View File

@@ -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,