Added edge swipe support for along nav bar direction

Added edge swipe from right to left and left to right on nav bar in
portrait. Also added quick switch action to apply a global setting to
switch between quick scrub and quick switch.

Test: atest QuickStepControllerTest
Bug: 112934365
Change-Id: I0d00608635bda63b3f77f12ec0b67b85f24a633c
This commit is contained in:
Matthew Ng
2018-12-06 17:15:27 -08:00
parent 3c359caa68
commit b9c8428daf
9 changed files with 326 additions and 119 deletions

View File

@@ -23,6 +23,8 @@
<dimen name="navigation_bar_size">@*android:dimen/navigation_bar_height</dimen>
<!-- Minimum swipe distance to catch the swipe gestures to invoke assist or switch tasks. -->
<dimen name="navigation_bar_min_swipe_distance">48dp</dimen>
<!-- The distance from a side of device of the navigation bar to start an edge swipe -->
<dimen name="navigation_bar_edge_swipe_threshold">60dp</dimen>
<!-- thickness (height) of the dead zone at the top of the navigation bar,
reducing false presses on navbar buttons; approx 2mm -->

View File

@@ -55,6 +55,11 @@ public class NavigationBackAction extends NavigationGestureAction {
super(navigationBarView, service);
}
@Override
public boolean allowHitTargetToMoveOverDrag() {
return true;
}
@Override
public boolean canPerformAction() {
return mProxySender.getBackButtonAlpha() > 0;

View File

@@ -154,6 +154,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
private QuickScrubAction mQuickScrubAction;
private QuickStepAction mQuickStepAction;
private NavigationBackAction mBackAction;
private QuickSwitchAction mQuickSwitchAction;
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -326,9 +327,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mQuickScrubAction = new QuickScrubAction(this, mOverviewProxyService);
mQuickStepAction = new QuickStepAction(this, mOverviewProxyService);
mBackAction = new NavigationBackAction(this, mOverviewProxyService);
mQuickSwitchAction = new QuickSwitchAction(this, mOverviewProxyService);
mDefaultGestureMap = new NavigationGestureAction[] {
mQuickStepAction, null /* swipeDownAction*/, null /* swipeLeftAction */,
mQuickScrubAction
mQuickScrubAction, null /* swipeLeftEdgeAction */, null /* swipeRightEdgeAction */
};
mPrototypeController = new NavigationPrototypeController(mHandler, mContext);
@@ -359,7 +361,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
getNavigationActionFromType(assignedMap[0], mDefaultGestureMap[0]),
getNavigationActionFromType(assignedMap[1], mDefaultGestureMap[1]),
getNavigationActionFromType(assignedMap[2], mDefaultGestureMap[2]),
getNavigationActionFromType(assignedMap[3], mDefaultGestureMap[3]));
getNavigationActionFromType(assignedMap[3], mDefaultGestureMap[3]),
getNavigationActionFromType(assignedMap[4], mDefaultGestureMap[4]),
getNavigationActionFromType(assignedMap[5], mDefaultGestureMap[5]));
}
}
@@ -372,6 +376,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
return mQuickScrubAction;
case NavigationPrototypeController.ACTION_BACK:
return mBackAction;
case NavigationPrototypeController.ACTION_QUICKSWITCH:
return mQuickSwitchAction;
default:
return defaultAction;
}

View File

@@ -112,7 +112,7 @@ public abstract class NavigationGestureAction {
/**
* @return whether or not to move the button that started gesture over with user input drag
*/
public boolean requiresDragWithHitTarget() {
public boolean allowHitTargetToMoveOverDrag() {
return false;
}
@@ -139,9 +139,9 @@ public abstract class NavigationGestureAction {
* Tell if action is enabled. Compared to {@link #canPerformAction()} this is based on settings
* if the action is disabled for a particular gesture. For example a back action can be enabled
* however if there is nothing to back to then {@link #canPerformAction()} should return false.
* In this way if the action requires {@link #requiresDragWithHitTarget()} then if enabled, the
* button can be dragged with a large dampening factor during the gesture but will not activate
* the action.
* In this way if the action requires {@link #allowHitTargetToMoveOverDrag()} then if enabled,
* the button can be dragged with a large dampening factor during the gesture but will not
* activate the action.
* @return true if this action is enabled and can run
*/
public abstract boolean isEnabled();

View File

@@ -24,7 +24,6 @@ import android.os.Handler;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -46,6 +45,7 @@ public class NavigationPrototypeController extends ContentObserver {
static final int ACTION_QUICKSTEP = 1;
static final int ACTION_QUICKSCRUB = 2;
static final int ACTION_BACK = 3;
static final int ACTION_QUICKSWITCH = 4;
private OnPrototypeChangedListener mListener;
@@ -53,7 +53,7 @@ public class NavigationPrototypeController extends ContentObserver {
* Each index corresponds to a different action set in QuickStepController
* {@see updateSwipeLTRBackSetting}
*/
private int[] mActionMap = new int[4];
private int[] mActionMap = new int[6];
private final Context mContext;

View File

@@ -18,8 +18,6 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.Interpolators.ALPHA_IN;
import static com.android.systemui.Interpolators.ALPHA_OUT;
import static com.android.systemui.recents.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
import static com.android.systemui.recents.OverviewProxyService.TAG_OPS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -31,11 +29,8 @@ import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.os.RemoteException;
import android.util.FloatProperty;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@@ -46,7 +41,7 @@ import com.android.systemui.shared.recents.utilities.Utilities;
/**
* QuickScrub action to send to launcher to start quickscrub gesture
*/
public class QuickScrubAction extends NavigationGestureAction {
public class QuickScrubAction extends QuickSwitchAction {
private static final String TAG = "QuickScrubAction";
private static final float TRACK_SCALE = 0.95f;
@@ -65,7 +60,6 @@ public class QuickScrubAction extends NavigationGestureAction {
private final int mTrackThickness;
private final int mTrackEndPadding;
private final Paint mTrackPaint = new Paint();
private final Rect mTrackRect = new Rect();
private final FloatProperty<QuickScrubAction> mTrackAlphaProperty =
new FloatProperty<QuickScrubAction>("TrackAlpha") {
@@ -177,7 +171,7 @@ public class QuickScrubAction extends NavigationGestureAction {
x1 = mNavigationBarView.getPaddingStart() + mTrackEndPadding;
x2 = x1 + width - 2 * mTrackEndPadding;
}
mTrackRect.set(x1, y1, x2, y2);
mDragOverRect.set(x1, y1, x2, y2);
}
@Override
@@ -194,15 +188,16 @@ public class QuickScrubAction extends NavigationGestureAction {
mTrackPaint.setAlpha(Math.round(255f * mTrackAlpha));
// Scale the track, but apply the inverse scale from the nav bar
final float radius = mTrackRect.height() / 2;
final float radius = mDragOverRect.height() / 2;
canvas.save();
float translate = Utilities.clamp(mHighlightCenter, mTrackRect.left, mTrackRect.right);
float translate = Utilities.clamp(mHighlightCenter, mDragOverRect.left,
mDragOverRect.right);
canvas.translate(translate, 0);
canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
1f / mNavigationBarView.getScaleY(),
mTrackRect.centerX(), mTrackRect.centerY());
canvas.drawRoundRect(mTrackRect.left - translate, mTrackRect.top,
mTrackRect.right - translate, mTrackRect.bottom, radius, radius, mTrackPaint);
mDragOverRect.centerX(), mDragOverRect.centerY());
canvas.drawRoundRect(mDragOverRect.left - translate, mDragOverRect.top,
mDragOverRect.right - translate, mDragOverRect.bottom, radius, radius, mTrackPaint);
canvas.restore();
}
@@ -211,11 +206,6 @@ public class QuickScrubAction extends NavigationGestureAction {
return mNavigationBarView.isQuickScrubEnabled();
}
@Override
public boolean disableProxyEvents() {
return true;
}
@Override
protected void onGestureStart(MotionEvent event) {
updateHighlight();
@@ -231,42 +221,12 @@ public class QuickScrubAction extends NavigationGestureAction {
mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
mTrackAnimator.start();
// Disable slippery for quick scrub to not cancel outside the nav bar
mNavigationBarView.updateSlippery();
try {
mProxySender.getProxy().onQuickScrubStart();
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Quick Scrub Start");
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to send start of quick scrub.", e);
}
mProxySender.notifyQuickScrubStarted();
startQuickGesture(event);
}
@Override
public void onGestureMove(int x, int y) {
int trackSize, offset;
if (isNavBarVertical()) {
trackSize = mTrackRect.height();
offset = y - mTrackRect.top;
} else {
offset = x - mTrackRect.left;
trackSize = mTrackRect.width();
}
if (!mDragHorizontalPositive || !mDragVerticalPositive) {
offset -= isNavBarVertical() ? mTrackRect.height() : mTrackRect.width();
}
float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
try {
mProxySender.getProxy().onQuickScrubProgress(scrubFraction);
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to send progress of quick scrub.", e);
}
super.onGestureMove(x, y);
mHighlightCenter = x;
mNavigationBarView.invalidate();
}
@@ -278,14 +238,7 @@ public class QuickScrubAction extends NavigationGestureAction {
private void endQuickScrub(boolean animate) {
animateEnd();
try {
mProxySender.getProxy().onQuickScrubEnd();
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Quick Scrub End");
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to send end of quick scrub.", e);
}
endQuickGesture(animate);
if (!animate) {
if (mTrackAnimator != null) {
mTrackAnimator.end();
@@ -295,7 +248,7 @@ public class QuickScrubAction extends NavigationGestureAction {
}
private void updateHighlight() {
if (mTrackRect.isEmpty()) {
if (mDragOverRect.isEmpty()) {
return;
}
int colorBase, colorGrad;
@@ -306,8 +259,8 @@ public class QuickScrubAction extends NavigationGestureAction {
colorBase = getContext().getColor(R.color.quick_step_track_background_background_light);
colorGrad = getContext().getColor(R.color.quick_step_track_background_foreground_light);
}
final RadialGradient mHighlight = new RadialGradient(0, mTrackRect.height() / 2,
mTrackRect.width() * GRADIENT_WIDTH, colorGrad, colorBase,
final RadialGradient mHighlight = new RadialGradient(0, mDragOverRect.height() / 2,
mDragOverRect.width() * GRADIENT_WIDTH, colorGrad, colorBase,
Shader.TileMode.CLAMP);
mTrackPaint.setShader(mHighlight);
}

View File

@@ -76,7 +76,9 @@ public class QuickStepController implements GestureHelper {
private static final int ACTION_SWIPE_DOWN_INDEX = 1;
private static final int ACTION_SWIPE_LEFT_INDEX = 2;
private static final int ACTION_SWIPE_RIGHT_INDEX = 3;
private static final int MAX_GESTURES = 4;
private static final int ACTION_SWIPE_LEFT_FROM_EDGE_INDEX = 4;
private static final int ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX = 5;
private static final int MAX_GESTURES = 6;
private NavigationBarView mNavigationBarView;
@@ -97,6 +99,7 @@ public class QuickStepController implements GestureHelper {
private float mMaxDragLimit;
private float mMinDragLimit;
private float mDragDampeningFactor;
private float mEdgeSwipeThreshold;
private NavigationGestureAction mCurrentAction;
private NavigationGestureAction[] mGestureActions = new NavigationGestureAction[MAX_GESTURES];
@@ -128,15 +131,21 @@ public class QuickStepController implements GestureHelper {
* @param swipeDownAction action after swiping down
* @param swipeLeftAction action after swiping left
* @param swipeRightAction action after swiping right
* @param swipeLeftFromEdgeAction action swiping left starting from the right side
* @param swipeRightFromEdgeAction action swiping right starting from the left side
*/
public void setGestureActions(@Nullable NavigationGestureAction swipeUpAction,
@Nullable NavigationGestureAction swipeDownAction,
@Nullable NavigationGestureAction swipeLeftAction,
@Nullable NavigationGestureAction swipeRightAction) {
@Nullable NavigationGestureAction swipeRightAction,
@Nullable NavigationGestureAction swipeLeftFromEdgeAction,
@Nullable NavigationGestureAction swipeRightFromEdgeAction) {
mGestureActions[ACTION_SWIPE_UP_INDEX] = swipeUpAction;
mGestureActions[ACTION_SWIPE_DOWN_INDEX] = swipeDownAction;
mGestureActions[ACTION_SWIPE_LEFT_INDEX] = swipeLeftAction;
mGestureActions[ACTION_SWIPE_RIGHT_INDEX] = swipeRightAction;
mGestureActions[ACTION_SWIPE_LEFT_FROM_EDGE_INDEX] = swipeLeftFromEdgeAction;
mGestureActions[ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX] = swipeRightFromEdgeAction;
// Set the current state to all actions
for (NavigationGestureAction action: mGestureActions) {
@@ -233,6 +242,8 @@ public class QuickStepController implements GestureHelper {
mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
mAllowGestureDetection = true;
mNotificationsVisibleOnDown = !mNavigationBarView.isNotificationsFullyCollapsed();
mEdgeSwipeThreshold = mContext.getResources()
.getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
break;
}
case MotionEvent.ACTION_MOVE: {
@@ -284,13 +295,17 @@ public class QuickStepController implements GestureHelper {
}
} else if (exceededSwipeHorizontalTouchSlop) {
if (mDragHPositive ? (posH < touchDownH) : (posH > touchDownH)) {
// Swiping left (ltr) gesture
tryToStartGesture(mGestureActions[ACTION_SWIPE_LEFT_INDEX],
true /* alignedWithNavBar */, event);
// Swiping left (rtl) gesture
int index = isEdgeSwipeAlongNavBar(touchDownH, !mDragHPositive)
? ACTION_SWIPE_LEFT_FROM_EDGE_INDEX : ACTION_SWIPE_LEFT_INDEX;
tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
event);
} else {
// Swiping right (ltr) gesture
tryToStartGesture(mGestureActions[ACTION_SWIPE_RIGHT_INDEX],
true /* alignedWithNavBar */, event);
int index = isEdgeSwipeAlongNavBar(touchDownH, mDragHPositive)
? ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX : ACTION_SWIPE_RIGHT_INDEX;
tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
event);
}
}
}
@@ -333,6 +348,17 @@ public class QuickStepController implements GestureHelper {
return mCurrentAction != null || deadZoneConsumed;
}
private boolean isEdgeSwipeAlongNavBar(int touchDown, boolean dragPositiveDirection) {
// Detect edge swipe from side of 0 -> threshold
if (dragPositiveDirection) {
return touchDown < mEdgeSwipeThreshold;
}
// Detect edge swipe from side of size -> (size - threshold)
final int largeSide = isNavBarVertical()
? mNavigationBarView.getHeight() : mNavigationBarView.getWidth();
return touchDown > largeSide - mEdgeSwipeThreshold;
}
private void handleDragHitTarget(int position, int touchDown) {
// Drag the hit target if gesture action requires it
if (mHitTarget != null && (mGestureVerticalDragsButton || mGestureHorizontalDragsButton)) {
@@ -480,7 +506,7 @@ public class QuickStepController implements GestureHelper {
event.transform(mTransformLocalMatrix);
// Calculate the bounding limits of drag to avoid dragging off nav bar's window
if (action.requiresDragWithHitTarget() && mHitTarget != null) {
if (action.allowHitTargetToMoveOverDrag() && mHitTarget != null) {
final int[] buttonCenter = new int[2];
View button = mHitTarget.getCurrentView();
button.getLocationInWindow(buttonCenter);
@@ -505,7 +531,7 @@ public class QuickStepController implements GestureHelper {
// Handle direction of the hit target drag from the axis that started the gesture
// Also calculate the dampening factor, weaker dampening if there is an active action
if (action.requiresDragWithHitTarget()) {
if (action.allowHitTargetToMoveOverDrag()) {
if (alignedWithNavBar) {
mGestureHorizontalDragsButton = true;
mGestureVerticalDragsButton = false;

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2018 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.systemui.statusbar.phone;
import static com.android.systemui.recents.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
import static com.android.systemui.recents.OverviewProxyService.TAG_OPS;
import android.annotation.NonNull;
import android.graphics.Rect;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
import android.view.MotionEvent;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.shared.recents.utilities.Utilities;
/**
* QuickSwitch action to send to launcher
*/
public class QuickSwitchAction extends NavigationGestureAction {
private static final String TAG = "QuickSwitchAction";
private static final String QUICKSWITCH_ENABLED_SETTING = "QUICK_SWITCH";
protected final Rect mDragOverRect = new Rect();
public QuickSwitchAction(@NonNull NavigationBarView navigationBar,
@NonNull OverviewProxyService service) {
super(navigationBar, service);
}
@Override
public void setBarState(boolean changed, int navBarPos, boolean dragHorPositive,
boolean dragVerPositive) {
super.setBarState(changed, navBarPos, dragHorPositive, dragVerPositive);
if (changed && isActive()) {
// End quickscrub if the state changes mid-transition
endQuickGesture(false /* animate */);
}
}
@Override
public boolean isEnabled() {
return mNavigationBarView.isQuickScrubEnabled();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mDragOverRect.set(top, left, right, bottom);
}
@Override
public boolean disableProxyEvents() {
return true;
}
@Override
protected void onGestureStart(MotionEvent event) {
// Temporarily enable launcher to allow quick switch instead of quick scrub
Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
QUICKSWITCH_ENABLED_SETTING, 1 /* enabled */);
startQuickGesture(event);
}
@Override
public void onGestureMove(int x, int y) {
int dragLength, offset;
if (isNavBarVertical()) {
dragLength = mDragOverRect.height();
offset = y - mDragOverRect.top;
} else {
offset = x - mDragOverRect.left;
dragLength = mDragOverRect.width();
}
if (!mDragHorizontalPositive || !mDragVerticalPositive) {
offset -= dragLength;
}
float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / dragLength, 0, 1);
try {
mProxySender.getProxy().onQuickScrubProgress(scrubFraction);
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Quick Switch Progress:" + scrubFraction);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to send progress of quick switch.", e);
}
}
@Override
protected void onGestureEnd() {
endQuickGesture(true /* animate */);
// Disable launcher to use quick switch instead of quick scrub
Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
QUICKSWITCH_ENABLED_SETTING, 0 /* disabled */);
}
protected void startQuickGesture(MotionEvent event) {
// Disable slippery for quick scrub to not cancel outside the nav bar
mNavigationBarView.updateSlippery();
try {
mProxySender.getProxy().onQuickScrubStart();
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Quick Scrub Start");
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to send start of quick scrub.", e);
}
mProxySender.notifyQuickScrubStarted();
}
protected void endQuickGesture(boolean animate) {
try {
mProxySender.getProxy().onQuickScrubEnd();
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Quick Scrub End");
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to send end of quick scrub.", e);
}
}
}

View File

@@ -61,6 +61,10 @@ import org.mockito.MockitoAnnotations;
@RunWithLooper
@SmallTest
public class QuickStepControllerTest extends SysuiTestCase {
private static final int NAVBAR_WIDTH = 1000;
private static final int NAVBAR_HEIGHT = 300;
private static final int EDGE_THRESHOLD = 100;
private QuickStepController mController;
private NavigationBarView mNavigationBarView;
private StatusBar mStatusBar;
@@ -73,6 +77,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
final ButtonDispatcher backButton = mock(ButtonDispatcher.class);
mResources = mock(Resources.class);
doReturn(EDGE_THRESHOLD).when(mResources)
.getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
mProxyService = mock(OverviewProxyService.class);
mProxy = mock(IOverviewProxy.Stub.class);
@@ -109,7 +115,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
public void testNoGesturesWhenSwipeUpDisabled() throws Exception {
doReturn(false).when(mProxyService).shouldShowSwipeUpUI();
mController.setGestureActions(mockAction(true), null /* swipeDownAction */,
null /* swipeLeftAction */, null /* swipeRightAction */);
null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
null /* rightEdgeSwipe */);
MotionEvent ev = event(MotionEvent.ACTION_DOWN, 1, 1);
assertFalse(mController.onInterceptTouchEvent(ev));
@@ -124,7 +131,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
// Add enabled gesture action
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
null /* swipeLeftAction */, null /* swipeRightAction */);
null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
null /* rightEdgeSwipe */);
assertFalse(mController.onInterceptTouchEvent(ev));
verify(mNavigationBarView, times(1)).requestUnbufferedDispatch(ev);
@@ -140,7 +148,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
// Add enabled gesture action
mController.setGestureActions(mockAction(true), null /* swipeDownAction */,
null /* swipeLeftAction */, null /* swipeRightAction */);
null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
null /* rightEdgeSwipe */);
// Set the gesture on deadzone
doReturn(null).when(mProxyService).getProxy();
@@ -165,7 +174,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
@Test
public void testOnTouchIgnoredDownEventAfterOnIntercept() {
mController.setGestureActions(mockAction(true), null /* swipeDownAction */,
null /* swipeLeftAction */, null /* swipeRightAction */);
null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
null /* rightEdgeSwipe */);
MotionEvent ev = event(MotionEvent.ACTION_DOWN, 1, 1);
assertFalse(touch(ev));
@@ -178,29 +188,45 @@ public class QuickStepControllerTest extends SysuiTestCase {
@Test
public void testGesturesCallCorrectAction() throws Exception {
doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
NavigationGestureAction swipeUp = mockAction(true);
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
NavigationGestureAction swipeLeftFromEdge = mockAction(true);
NavigationGestureAction swipeRightFromEdge = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
swipeRightFromEdge);
// Swipe Up
assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
// Swipe Down
assertGestureTriggersAction(swipeDown, 1, 1, 5, 100);
// Swipe Left
assertGestureTriggersAction(swipeLeft, 100, 1, 5, 1);
assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeRight, 1, 1, 100, 5);
assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 5);
// Swipe Left from Edge
assertGestureTriggersAction(swipeLeftFromEdge, NAVBAR_WIDTH, 1, 5, 1);
// Swipe Right from Edge
assertGestureTriggersAction(swipeRightFromEdge, 0, 1, NAVBAR_WIDTH, 5);
}
@Test
public void testGesturesCallCorrectActionLandscape() throws Exception {
doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
NavigationGestureAction swipeUp = mockAction(true);
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
NavigationGestureAction swipeLeftFromEdge = mockAction(true);
NavigationGestureAction swipeRightFromEdge = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
swipeRightFromEdge);
// In landscape
mController.setBarState(false /* isRTL */, NAV_BAR_RIGHT);
@@ -208,34 +234,50 @@ public class QuickStepControllerTest extends SysuiTestCase {
// Swipe Up
assertGestureTriggersAction(swipeRight, 1, 100, 5, 1);
// Swipe Down
assertGestureTriggersAction(swipeLeft, 1, 1, 5, 100);
assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
// Swipe Up from Edge
assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
// Swipe Down from Edge
assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
public void testGesturesCallCorrectActionSeascape() throws Exception {
doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
mController.setBarState(false /* isRTL */, NAV_BAR_LEFT);
NavigationGestureAction swipeUp = mockAction(true);
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
NavigationGestureAction swipeLeftFromEdge = mockAction(true);
NavigationGestureAction swipeRightFromEdge = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
swipeRightFromEdge);
// Swipe Up
assertGestureTriggersAction(swipeLeft, 1, 100, 5, 1);
assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
// Swipe Down
assertGestureTriggersAction(swipeRight, 1, 1, 5, 100);
assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
// Swipe Up from Edge
assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
// Swipe Down from Edge
assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
public void testGesturesCallCorrectActionRTL() throws Exception {
doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
mController.setBarState(true /* isRTL */, NAV_BAR_BOTTOM);
// The swipe gestures below are for LTR, so RTL in portrait will be swapped
@@ -243,20 +285,29 @@ public class QuickStepControllerTest extends SysuiTestCase {
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
NavigationGestureAction swipeLeftFromEdge = mockAction(true);
NavigationGestureAction swipeRightFromEdge = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
swipeRightFromEdge);
// Swipe Up in RTL
assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
// Swipe Down in RTL
assertGestureTriggersAction(swipeDown, 1, 1, 5, 100);
// Swipe Left in RTL
assertGestureTriggersAction(swipeRight, 100, 1, 5, 1);
assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, 5, 1);
// Swipe Right in RTL
assertGestureTriggersAction(swipeLeft, 1, 1, 100, 5);
assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 0);
// Swipe Left from Edge
assertGestureTriggersAction(swipeRightFromEdge, NAVBAR_WIDTH, 1, 5, 1);
// Swipe Right from Edge
assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, NAVBAR_WIDTH, 5);
}
@Test
public void testGesturesCallCorrectActionLandscapeRTL() throws Exception {
doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
mController.setBarState(true /* isRTL */, NAV_BAR_RIGHT);
// The swipe gestures below are for LTR, so RTL in landscape will be swapped
@@ -264,20 +315,29 @@ public class QuickStepControllerTest extends SysuiTestCase {
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
NavigationGestureAction swipeLeftFromEdge = mockAction(true);
NavigationGestureAction swipeRightFromEdge = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
swipeRightFromEdge);
// Swipe Up
assertGestureTriggersAction(swipeLeft, 1, 100, 5, 1);
assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
// Swipe Down
assertGestureTriggersAction(swipeRight, 1, 1, 5, 100);
assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
// Swipe Up from Edge
assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
// Swipe Down from Edge
assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
public void testGesturesCallCorrectActionSeascapeRTL() throws Exception {
doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
mController.setBarState(true /* isRTL */, NAV_BAR_LEFT);
// The swipe gestures below are for LTR, so RTL in seascape will be swapped
@@ -285,16 +345,23 @@ public class QuickStepControllerTest extends SysuiTestCase {
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
NavigationGestureAction swipeLeftFromEdge = mockAction(true);
NavigationGestureAction swipeRightFromEdge = mockAction(true);
mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
swipeRightFromEdge);
// Swipe Up
assertGestureTriggersAction(swipeRight, 1, 100, 5, 1);
assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, 1);
// Swipe Down
assertGestureTriggersAction(swipeLeft, 1, 1, 5, 100);
assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
// Swipe Up from Edge
assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
// Swipe Down from Edge
assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -305,7 +372,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
// Add enabled gesture action
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
null /* swipeLeftAction */, null /* swipeRightAction */);
null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
null /* rightEdgeSwipe */);
// Touch down to begin swipe
MotionEvent downEvent = event(MotionEvent.ACTION_DOWN, 1, 100);
@@ -326,7 +394,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
NavigationGestureAction action = mockAction(true);
doReturn(false).when(action).canRunWhenNotificationsShowing();
mController.setGestureActions(action, null /* swipeDownAction */,
null /* swipeLeftAction */, null /* swipeRightAction */);
null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
null /* rightEdgeSwipe */);
// Show the notifications
doReturn(false).when(mNavigationBarView).isNotificationsFullyCollapsed();
@@ -351,7 +420,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
public void testActionCannotPerform() throws Exception {
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
null /* swipeLeftAction */, null /* swipeRightAction */);
null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
null /* rightEdgeSwipe */);
// Cannot perform action
doReturn(false).when(action).canPerformAction();
@@ -374,13 +444,17 @@ public class QuickStepControllerTest extends SysuiTestCase {
@Test
public void testQuickScrub() throws Exception {
doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
QuickScrubAction action = spy(new QuickScrubAction(mNavigationBarView, mProxyService));
mController.setGestureActions(null /* swipeUpAction */, null /* swipeDownAction */,
null /* swipeLeftAction */, action);
null /* swipeLeftAction */, action, null /* leftEdgeSwipe */,
null /* rightEdgeSwipe */);
int x = NAVBAR_WIDTH / 2;
int y = 20;
// Set the layout and other padding to make sure the scrub fraction is calculated correctly
action.onLayout(true, 0, 0, 400, 100);
action.onLayout(true, 0, 0, NAVBAR_WIDTH, NAVBAR_HEIGHT);
doReturn(0).when(mNavigationBarView).getPaddingLeft();
doReturn(0).when(mNavigationBarView).getPaddingRight();
doReturn(0).when(mNavigationBarView).getPaddingStart();
@@ -393,14 +467,14 @@ public class QuickStepControllerTest extends SysuiTestCase {
doReturn(true).when(mNavigationBarView).isQuickScrubEnabled();
// Touch down
MotionEvent downEvent = event(MotionEvent.ACTION_DOWN, 0, y);
MotionEvent downEvent = event(MotionEvent.ACTION_DOWN, x, y);
assertFalse(touch(downEvent));
assertNull(mController.getCurrentAction());
verify(mProxy, times(1)).onPreMotionEvent(mNavigationBarView.getDownHitTarget());
verify(mProxy, times(1)).onMotionEvent(downEvent);
// Move to start trigger action from gesture
MotionEvent moveEvent1 = event(MotionEvent.ACTION_MOVE, 100, y);
MotionEvent moveEvent1 = event(MotionEvent.ACTION_MOVE, x + 100, y);
assertTrue(touch(moveEvent1));
assertEquals(action, mController.getCurrentAction());
verify(action, times(1)).onGestureStart(moveEvent1);
@@ -410,11 +484,13 @@ public class QuickStepControllerTest extends SysuiTestCase {
verify(mProxy, never()).onMotionEvent(moveEvent1);
// Move again for scrub
MotionEvent moveEvent2 = event(MotionEvent.ACTION_MOVE, 200, y);
float fraction = 3f / 4;
x = (int) (NAVBAR_WIDTH * fraction);
MotionEvent moveEvent2 = event(MotionEvent.ACTION_MOVE, x, y);
assertTrue(touch(moveEvent2));
assertEquals(action, mController.getCurrentAction());
verify(action, times(1)).onGestureMove(200, y);
verify(mProxy, times(1)).onQuickScrubProgress(1f / 2);
verify(action, times(1)).onGestureMove(x, y);
verify(mProxy, times(1)).onQuickScrubProgress(fraction);
verify(mProxy, never()).onMotionEvent(moveEvent2);
// Action up
@@ -430,7 +506,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
public void testQuickStep() throws Exception {
QuickStepAction action = new QuickStepAction(mNavigationBarView, mProxyService);
mController.setGestureActions(action, null /* swipeDownAction */,
null /* swipeLeftAction */, null /* swipeRightAction */);
null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
null /* rightEdgeSwipe */);
// Notifications are up, should prevent quickstep
doReturn(false).when(mNavigationBarView).isNotificationsFullyCollapsed();
@@ -466,7 +543,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
public void testLongPressPreventDetection() throws Exception {
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
null /* swipeLeftAction */, null /* swipeRightAction */);
null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
null /* rightEdgeSwipe */);
// Start the drag up
assertFalse(touch(MotionEvent.ACTION_DOWN, 100, 1));
@@ -488,23 +566,21 @@ public class QuickStepControllerTest extends SysuiTestCase {
@Test
public void testHitTargetDragged() throws Exception {
final int navbarWidth = 1000;
final int navbarHeight = 1000;
ButtonDispatcher button = mock(ButtonDispatcher.class);
FakeLocationView buttonView = spy(new FakeLocationView(mContext, navbarWidth / 2,
navbarHeight / 2));
FakeLocationView buttonView = spy(new FakeLocationView(mContext, NAVBAR_WIDTH / 2,
NAVBAR_HEIGHT / 2));
doReturn(buttonView).when(button).getCurrentView();
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, action, action, action);
mController.setGestureActions(action, action, action, action, action, action);
// Setup getting the hit target
doReturn(HIT_TARGET_HOME).when(action).requiresTouchDownHitTarget();
doReturn(true).when(action).requiresDragWithHitTarget();
doReturn(true).when(action).allowHitTargetToMoveOverDrag();
doReturn(HIT_TARGET_HOME).when(mNavigationBarView).getDownHitTarget();
doReturn(button).when(mNavigationBarView).getHomeButton();
doReturn(navbarWidth).when(mNavigationBarView).getWidth();
doReturn(navbarHeight).when(mNavigationBarView).getHeight();
doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
// Portrait
assertGestureDragsHitTargetAllDirections(buttonView, false /* isRTL */, NAV_BAR_BOTTOM);