Remove hover-to-launch gesture for shortcuts.

- You can no longer long press and drag over shortcuts before
  lifting to launch them.
- Dragging in any direction past a threshold enters spring-loaded mode.

Bug: 28980830
Change-Id: I36bfc379cc983017456a3ef0314faa1ac9691c36
This commit is contained in:
Tony Wickham
2016-07-26 15:13:38 -07:00
parent 8c06310b06
commit bf0ee9a305
2 changed files with 11 additions and 123 deletions
@@ -23,7 +23,6 @@ import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.support.annotation.IntDef;
import android.util.AttributeSet;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
@@ -40,26 +39,8 @@ import com.android.launcher3.util.PillRevealOutlineProvider;
*/
public class DeepShortcutView extends FrameLayout {
private static final float HOVER_SCALE = 1.05f;
// The direction this view should translate when animating the hover state.
// This allows hovered shortcuts to "push" other shortcuts away.
@IntDef({DIRECTION_UP, DIRECTION_NONE, DIRECTION_DOWN})
public @interface TranslationDirection {}
public static final int DIRECTION_UP = -1;
public static final int DIRECTION_NONE = 0;
public static final int DIRECTION_DOWN = 1;
@TranslationDirection
private int mTranslationDirection = DIRECTION_NONE;
private int mSpacing;
private int mRadius;
private Rect mPillRect;
private int mTop;
private boolean mIsHoveringOver = false;
private LauncherViewPropertyAnimator mHoverAnimator;
private BubbleTextView mBubbleText;
@@ -74,10 +55,8 @@ public class DeepShortcutView extends FrameLayout {
public DeepShortcutView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mSpacing = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_spacing);
mRadius = getResources().getDimensionPixelSize(R.dimen.bg_pill_radius);
mPillRect = new Rect();
mHoverAnimator = new LauncherViewPropertyAnimator(this);
}
@Override
@@ -146,53 +125,4 @@ public class DeepShortcutView extends FrameLayout {
openAnimation.setInterpolator(new DecelerateInterpolator());
return openAnimation;
}
/**
* Updates the state of this view based on touches over the container before user lifts finger.
*
* @param containerContainsTouch whether the {@link DeepShortcutsContainer} this shortcut
* is inside contains the current touch
* @param isBelowHoveredShortcut whether a sibling shortcut before this one in the
* view hierarchy is being hovered over
* @param touchY the y coordinate of the touch, relative to the {@link DeepShortcutsContainer}
* this shortcut is inside
* @return whether this shortcut is being hovered over
*/
public boolean updateHoverState(boolean containerContainsTouch, boolean isBelowHoveredShortcut,
float touchY) {
if (!containerContainsTouch) {
mIsHoveringOver = false;
mTranslationDirection = DIRECTION_NONE;
} else if (isBelowHoveredShortcut) {
mIsHoveringOver = false;
mTranslationDirection = DIRECTION_DOWN;
} else {
// Include space around the view when determining hover state to avoid gaps.
mTop = (int) (getY() - getTranslationY());
mIsHoveringOver = (touchY >= mTop - mSpacing / 2)
&& (touchY < mTop + getHeight() + mSpacing / 2);
mTranslationDirection = mIsHoveringOver ? DIRECTION_NONE : DIRECTION_UP;
}
animateHoverState();
return mIsHoveringOver;
}
/**
* If this shortcut is being hovered over, we scale it up. If another shortcut is being hovered
* over, we translate this one away from it to account for its increased size.
*/
private void animateHoverState() {
if (mHoverAnimator.isRunning()) {
return;
}
float scale = mIsHoveringOver ? HOVER_SCALE : 1f;
float translateY = (HOVER_SCALE - 1f) * getHeight() * mTranslationDirection;
mHoverAnimator.scaleX(scale).scaleY(scale).translationY(translateY)
.setDuration(getResources().getInteger(R.integer.config_deepShortcutHoverDuration))
.start();
}
public boolean isHoveringOver() {
return mIsHoveringOver;
}
}
@@ -16,8 +16,6 @@
package com.android.launcher3.shortcuts;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.content.ComponentName;
@@ -89,7 +87,6 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC
private Point mIconLastTouchPos = new Point();
private boolean mIsLeftAligned;
private boolean mIsAboveIcon;
private boolean mIsAnimatingOpen;
private boolean mSrcIconDragStarted;
@@ -233,13 +230,6 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC
int animationIndex = mIsAboveIcon ? numShortcuts - i - 1 : i;
shortcutAnims.play(deepShortcutView.createOpenAnimation(animationIndex, mIsAboveIcon));
}
shortcutAnims.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mIsAnimatingOpen = false;
}
});
mIsAnimatingOpen = true;
shortcutAnims.start();
}
@@ -348,7 +338,6 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC
Utilities.translateEventCoordinates(this, mLauncher.getDragLayer(), ev);
final int dragLayerX = (int) ev.getX();
final int dragLayerY = (int) ev.getY();
int childCount = getChildCount();
if (action == MotionEvent.ACTION_MOVE) {
if (mLastX != 0 || mLastY != 0) {
mDistanceDragged += Math.hypot(mLastX - x, mLastY - y);
@@ -356,48 +345,22 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC
mLastX = x;
mLastY = y;
boolean containerContainsTouch = x >= 0 && y >= 0 && x < getWidth() && y < getHeight();
if (shouldStartDeferredDrag((int) x, (int) y, containerContainsTouch)) {
if (shouldStartDeferredDrag((int) x, (int) y)) {
mSrcIconDragStarted = true;
cleanupDeferredDrag(true);
mDeferredDragIcon.getParent().requestDisallowInterceptTouchEvent(false);
mDeferredDragIcon.getOnLongClickListener().onLongClick(mDeferredDragIcon);
mLauncher.getDragController().onTouchEvent(ev);
return true;
} else {
// Determine whether touch is over a shortcut.
boolean hoveringOverShortcut = false;
for (int i = 0; i < childCount && !mIsAnimatingOpen; i++) {
DeepShortcutView shortcut = getShortcutAt(i);
if (shortcut.updateHoverState(containerContainsTouch, hoveringOverShortcut, y)) {
hoveringOverShortcut = true;
}
}
if (!hoveringOverShortcut && mDistanceDragged > mDragDeadzone) {
// After dragging further than a small deadzone,
// have the drag view follow the user's finger.
mDragView.setVisibility(VISIBLE);
mDragView.move(dragLayerX, dragLayerY);
mDeferredDragIcon.setVisibility(INVISIBLE);
} else if (hoveringOverShortcut) {
// Jump drag view back to original place on grid,
// so user doesn't think they are still dragging.
// TODO: can we improve this interaction? maybe with a ghost icon or similar?
mDragView.setVisibility(INVISIBLE);
mDeferredDragIcon.setVisibility(VISIBLE);
}
} else if (mDistanceDragged > mDragDeadzone) {
// After dragging further than a small deadzone,
// have the drag view follow the user's finger.
mDragView.setVisibility(VISIBLE);
mDragView.move(dragLayerX, dragLayerY);
mDeferredDragIcon.setVisibility(INVISIBLE);
}
} else if (action == MotionEvent.ACTION_UP) {
cleanupDeferredDrag(true);
// Launch a shortcut if user was hovering over it.
for (int i = 0; i < childCount; i++) {
DeepShortcutView shortcut = getShortcutAt(i);
if (shortcut.isHoveringOver()) {
shortcut.getBubbleText().performClick();
break;
}
}
} else if (action == MotionEvent.ACTION_CANCEL) {
// Do not change the source icon visibility if we are already dragging the source icon.
cleanupDeferredDrag(!mSrcIconDragStarted);
@@ -410,19 +373,14 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC
* relative to the original icon and the shortcuts container.
*
* Current behavior:
* - Compute distance from original touch down to closest container edge.
* - Compute distance from latest touch (given x and y) and compare to original distance;
* if the new distance is larger than a threshold, the deferred drag should start.
* - Never defer the drag if this container contains the touch.
* - Start the drag if the touch passes a certain distance from the original touch down.
*
* @param x the x touch coordinate relative to this container
* @param y the y touch coordinate relative to this container
*/
private boolean shouldStartDeferredDrag(int x, int y, boolean containerContainsTouch) {
int closestEdgeY = mIsAboveIcon ? getMeasuredHeight() : 0;
double distToEdge = Math.abs(mTouchDown[1] - closestEdgeY);
double newDistToEdge = Math.hypot(x - mTouchDown[0], y - closestEdgeY);
return !containerContainsTouch && (newDistToEdge - distToEdge > mStartDragThreshold);
private boolean shouldStartDeferredDrag(int x, int y) {
double distFromTouchDown = Math.hypot(x - mTouchDown[0], y - mTouchDown[1]);
return distFromTouchDown > mStartDragThreshold;
}
public void cleanupDeferredDrag(boolean updateSrcVisibility) {