diff options
Diffstat (limited to 'src/com')
10 files changed, 162 insertions, 410 deletions
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index b6474e6ef..2b64d42d2 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -3109,7 +3109,17 @@ public class Launcher extends Activity longClickCellInfo.cellX, longClickCellInfo.cellY)); if (!(itemUnderLongClick instanceof Folder || isAllAppsButton)) { // User long pressed on an item - mWorkspace.startDrag(longClickCellInfo, new DragOptions()); + DragOptions dragOptions = new DragOptions(); + if (itemUnderLongClick instanceof BubbleTextView) { + BubbleTextView icon = (BubbleTextView) itemUnderLongClick; + if (icon.hasDeepShortcuts()) { + DeepShortcutsContainer dsc = DeepShortcutsContainer.showForIcon(icon); + if (dsc != null) { + dragOptions.deferDragCondition = dsc.createDeferDragCondition(null); + } + } + } + mWorkspace.startDrag(longClickCellInfo, dragOptions); } } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 0e25b1ef9..ea5401eb3 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -74,8 +74,6 @@ import com.android.launcher3.dragndrop.SpringLoadedDragController; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.graphics.DragPreviewProvider; -import com.android.launcher3.shortcuts.DeepShortcutManager; -import com.android.launcher3.shortcuts.ShortcutsContainerListener; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.ItemInfoMatcher; @@ -1175,10 +1173,6 @@ public class Workspace extends PagedView if (!(child instanceof Folder)) { child.setHapticFeedbackEnabled(false); child.setOnLongClickListener(mLongClickListener); - if (child instanceof BubbleTextView && DeepShortcutManager.supportsShortcuts(info)) { - // TODO: only add this listener if the item has shortcuts associated with it. - child.setOnTouchListener(new ShortcutsContainerListener((BubbleTextView) child)); - } } if (child instanceof DropTarget) { mDragController.addDropTarget((DropTarget) child); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 290accb1e..5892787f3 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -36,6 +36,7 @@ import android.view.ViewGroup; import com.android.launcher3.AppInfo; import com.android.launcher3.BaseContainerView; +import com.android.launcher3.BubbleTextView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeleteDropTarget; import com.android.launcher3.DeviceProfile; @@ -53,6 +54,7 @@ import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.folder.Folder; import com.android.launcher3.graphics.TintedDrawableSpan; import com.android.launcher3.keyboard.FocusedItemDecorator; +import com.android.launcher3.shortcuts.DeepShortcutsContainer; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.ComponentKey; @@ -542,13 +544,32 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc if (!mLauncher.isAppsViewVisible() || mLauncher.getWorkspace().isSwitchingState()) return false; - // Return if global dragging is not enabled + // Return if global dragging is not enabled or we are already dragging if (!mLauncher.isDraggingEnabled()) return false; + if (mLauncher.getDragController().isDragging()) return false; // Start the drag - mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions()); - // Enter spring loaded mode - mLauncher.enterSpringLoadedDragMode(); + DragOptions dragOptions = new DragOptions(); + if (v instanceof BubbleTextView) { + final BubbleTextView icon = (BubbleTextView) v; + if (icon.hasDeepShortcuts()) { + DeepShortcutsContainer dsc = DeepShortcutsContainer.showForIcon(icon); + if (dsc != null) { + dragOptions.deferDragCondition = dsc.createDeferDragCondition(new Runnable() { + @Override + public void run() { + icon.setVisibility(VISIBLE); + } + }); + } + } + } + mLauncher.getWorkspace().beginDragShared(v, this, dragOptions); + if (FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND) { + // Enter spring loaded mode (the new workspace does this in + // onDragStart(), so we don't want to do it here) + mLauncher.enterSpringLoadedDragMode(); + } return false; } @@ -598,7 +619,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc // target layout we were dropping on. if (!success) { boolean showOutOfSpaceMessage = false; - if (target instanceof Workspace) { + if (target instanceof Workspace && !mLauncher.getDragController().isDeferringDrag()) { int currentScreen = mLauncher.getCurrentWorkspaceScreen(); Workspace workspace = (Workspace) target; CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen); diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index 39ab58b8f..7b6aef16d 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -42,8 +42,6 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.shortcuts.DeepShortcutManager; -import com.android.launcher3.shortcuts.ShortcutsContainerListener; import java.util.HashMap; import java.util.List; @@ -503,10 +501,6 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter. AppInfo info = mApps.getAdapterItems().get(position).appInfo; BubbleTextView icon = (BubbleTextView) holder.mContent; icon.applyFromApplicationInfo(info); - if (DeepShortcutManager.supportsShortcuts(info)) { - // TODO: only add this listener if the item has shortcuts associated with it. - icon.setOnTouchListener(new ShortcutsContainerListener(icon)); - } icon.setAccessibilityDelegate(mLauncher.getAccessibilityDelegate()); break; } @@ -514,10 +508,6 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter. AppInfo info = mApps.getAdapterItems().get(position).appInfo; BubbleTextView icon = (BubbleTextView) holder.mContent; icon.applyFromApplicationInfo(info); - if (DeepShortcutManager.supportsShortcuts(info)) { - // TODO: only add this listener if the item has shortcuts associated with it. - icon.setOnTouchListener(new ShortcutsContainerListener(icon)); - } icon.setAccessibilityDelegate(mLauncher.getAccessibilityDelegate()); break; } diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index a93ee9019..6eb7dcc20 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -131,6 +131,8 @@ public class DragController implements DragDriver.EventListener, TouchController protected final int mFlingToDeleteThresholdVelocity; private VelocityTracker mVelocityTracker; + private boolean mIsDragDeferred; + /** * Interface to receive notifications when a drag starts or stops */ @@ -228,9 +230,14 @@ public class DragController implements DragDriver.EventListener, TouchController mDragObject = new DropTarget.DragObject(); + mIsDragDeferred = !mOptions.deferDragCondition.shouldStartDeferredDrag(0); + final Resources res = mLauncher.getResources(); - final float scaleDps = FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND ? - res.getDimensionPixelSize(R.dimen.dragViewScale) : 0f; + final float scaleDps = FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND + ? res.getDimensionPixelSize(R.dimen.dragViewScale) + : mIsDragDeferred + ? res.getDimensionPixelSize(R.dimen.deferred_drag_view_scale) + : 0f; final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX, registrationY, initialDragViewScale, scaleDps); @@ -264,8 +271,10 @@ public class DragController implements DragDriver.EventListener, TouchController dragView.show(mMotionDownX, mMotionDownY); mDistanceSinceScroll = 0; - for (DragListener listener : new ArrayList<>(mListeners)) { - listener.onDragStart(mDragObject, mOptions); + if (!mIsDragDeferred) { + startDeferredDrag(); + } else { + mOptions.deferDragCondition.onDeferredDragStart(); } mLastTouch[0] = mMotionDownX; @@ -275,8 +284,16 @@ public class DragController implements DragDriver.EventListener, TouchController return dragView; } - public Point getMotionDown() { - return new Point(mMotionDownX, mMotionDownY); + public boolean isDeferringDrag() { + return mIsDragDeferred; + } + + public void startDeferredDrag() { + for (DragListener listener : new ArrayList<>(mListeners)) { + listener.onDragStart(mDragObject, mOptions); + } + mOptions.deferDragCondition.onDragStart(); + mIsDragDeferred = false; } /** @@ -518,6 +535,11 @@ public class DragController implements DragDriver.EventListener, TouchController mLastTouch[0] = x; mLastTouch[1] = y; checkScrollState(x, y); + + if (mIsDragDeferred && mOptions.deferDragCondition.shouldStartDeferredDrag( + Math.hypot(x - mMotionDownX, y - mMotionDownY))) { + startDeferredDrag(); + } } public float getDistanceDragged() { @@ -715,6 +737,9 @@ public class DragController implements DragDriver.EventListener, TouchController mDragObject.dragSource.onDropCompleted( dropTargetAsView, mDragObject, flingVel != null, accepted); mLauncher.getUserEventDispatcher().logDragNDrop(mDragObject, dropTargetAsView); + if (mIsDragDeferred) { + mOptions.deferDragCondition.onDropBeforeDeferredDrag(); + } } private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) { diff --git a/src/com/android/launcher3/dragndrop/DragOptions.java b/src/com/android/launcher3/dragndrop/DragOptions.java index 3d52a48c6..dbf46f338 100644 --- a/src/com/android/launcher3/dragndrop/DragOptions.java +++ b/src/com/android/launcher3/dragndrop/DragOptions.java @@ -28,4 +28,44 @@ public class DragOptions { /** Specifies the start location for the system DnD, null when using internal DnD */ public Point systemDndStartPoint = null; + + /** Determines when a deferred drag should start. By default, drags aren't deferred at all. */ + public DeferDragCondition deferDragCondition = new DeferDragCondition(); + + /** + * Specifies a condition that must be met before DragListener#onDragStart() is called. + * By default, there is no condition and onDragStart() is called immediately following + * DragController#startDrag(). + * + * This condition can be overridden, and callbacks are provided for the following cases: + * - The drag starts, but onDragStart() is deferred (onDeferredDragStart()). + * - The drag ends before the condition is met (onDropBeforeDeferredDrag()). + * - The condition is met (onDragStart()). + */ + public static class DeferDragCondition { + public boolean shouldStartDeferredDrag(double distanceDragged) { + return true; + } + + /** + * The drag has started, but onDragStart() is deferred. + * This happens when shouldStartDeferredDrag() returns true. + */ + public void onDeferredDragStart() { + // Do nothing. + } + + /** + * User dropped before the deferred condition was met, + * i.e. before shouldStartDeferredDrag() returned true. + */ + public void onDropBeforeDeferredDrag() { + // Do nothing + } + + /** onDragStart() has been called, now we are in a normal drag. */ + public void onDragStart() { + // Do nothing + } + } } diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index b64d12c1d..a666b564d 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -51,6 +51,7 @@ import android.widget.TextView; import com.android.launcher3.Alarm; import com.android.launcher3.AppInfo; +import com.android.launcher3.BubbleTextView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DragSource; @@ -77,6 +78,7 @@ import com.android.launcher3.dragndrop.DragController.DragListener; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.pageindicators.PageIndicatorDots; +import com.android.launcher3.shortcuts.DeepShortcutsContainer; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.CircleRevealOutlineProvider; @@ -279,7 +281,17 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList public boolean onLongClick(View v) { // Return if global dragging is not enabled if (!mLauncher.isDraggingEnabled()) return true; - return startDrag(v, new DragOptions()); + DragOptions dragOptions = new DragOptions(); + if (v instanceof BubbleTextView) { + BubbleTextView icon = (BubbleTextView) v; + if (icon.hasDeepShortcuts()) { + DeepShortcutsContainer dsc = DeepShortcutsContainer.showForIcon(icon); + if (dsc != null) { + dragOptions.deferDragCondition = dsc.createDeferDragCondition(null); + } + } + } + return startDrag(v, dragOptions); } public boolean startDrag(View v, DragOptions options) { @@ -1297,7 +1309,9 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mIsExternalDrag = false; } else { currentDragView = mCurrentDragView; - mContent.addViewForRank(currentDragView, si, mEmptyCellRank); + if (!mDragController.isDeferringDrag()) { + mContent.addViewForRank(currentDragView, si, mEmptyCellRank); + } } if (d.dragView.hasDrawn()) { @@ -1318,9 +1332,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mItemsInvalidated = true; rearrangeChildren(); - // Temporarily suppress the listener, as we did all the work already here. - try (SuppressInfoChanges s = new SuppressInfoChanges()) { - mInfo.add(si, false); + if (!mDragController.isDeferringDrag()) { + // Temporarily suppress the listener, as we did all the work already here. + try (SuppressInfoChanges s = new SuppressInfoChanges()) { + mInfo.add(si, false); + } } // Clear the drag info, as it is no longer being dragged. diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java index 1171d488d..c6b06717f 100644 --- a/src/com/android/launcher3/folder/FolderPagedView.java +++ b/src/com/android/launcher3/folder/FolderPagedView.java @@ -44,10 +44,8 @@ import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace.ItemOperator; import com.android.launcher3.dragndrop.DragController; -import com.android.launcher3.pageindicators.PageIndicator; import com.android.launcher3.keyboard.ViewGroupFocusHelper; -import com.android.launcher3.shortcuts.DeepShortcutManager; -import com.android.launcher3.shortcuts.ShortcutsContainerListener; +import com.android.launcher3.pageindicators.PageIndicator; import com.android.launcher3.util.Thunk; import java.util.ArrayList; @@ -236,10 +234,6 @@ public class FolderPagedView extends PagedView { textView.applyFromShortcutInfo(item, mIconCache); textView.setOnClickListener(mFolder); textView.setOnLongClickListener(mFolder); - if (DeepShortcutManager.supportsShortcuts(item)) { - // TODO: only add this listener if the item has shortcuts associated with it. - textView.setOnTouchListener(new ShortcutsContainerListener(textView)); - } textView.setOnFocusChangeListener(mFocusIndicatorHelper); textView.setOnKeyListener(mKeyListener); diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java index 5ef128811..2702d4e8e 100644 --- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java +++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java @@ -34,16 +34,13 @@ import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; import android.view.Gravity; -import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityEvent; import android.view.animation.DecelerateInterpolator; import android.widget.LinearLayout; -import com.android.launcher3.AppInfo; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; @@ -59,7 +56,6 @@ import com.android.launcher3.LogAccelerateInterpolator; import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; -import com.android.launcher3.Workspace; import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.dragndrop.DragController; @@ -85,18 +81,12 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC private final Launcher mLauncher; private final DeepShortcutManager mDeepShortcutsManager; - private final int mDragDeadzone; private final int mStartDragThreshold; private final ShortcutMenuAccessibilityDelegate mAccessibilityDelegate; + private final boolean mIsRtl; private BubbleTextView mDeferredDragIcon; - private int mActivePointerId; - private int[] mTouchDown = null; - private DragView mDragView; - private float mLastX, mLastY; - private float mDistanceDragged = 0; private final Rect mTempRect = new Rect(); - private final int[] mTempXY = new int[2]; private Point mIconLastTouchPos = new Point(); private boolean mIsLeftAligned; private boolean mIsAboveIcon; @@ -106,16 +96,11 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC private boolean mDeferContainerRemoval; private boolean mIsOpen; - private boolean mSrcIconDragStarted; - private boolean mIsRtl; - private int mArrowHorizontalOffset; - public DeepShortcutsContainer(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mLauncher = Launcher.getLauncher(context); mDeepShortcutsManager = LauncherAppState.getInstance().getShortcutManager(); - mDragDeadzone = ViewConfiguration.get(context).getScaledTouchSlop(); mStartDragThreshold = getResources().getDimensionPixelSize( R.dimen.deep_shortcuts_start_drag_threshold); mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(mLauncher); @@ -134,7 +119,7 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC final Resources resources = getResources(); final int arrowWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcuts_arrow_width); final int arrowHeight = resources.getDimensionPixelSize(R.dimen.deep_shortcuts_arrow_height); - mArrowHorizontalOffset = resources.getDimensionPixelSize( + final int arrowHorizontalOffset = resources.getDimensionPixelSize( R.dimen.deep_shortcuts_arrow_horizontal_offset); final int arrowVerticalOffset = resources.getDimensionPixelSize( R.dimen.deep_shortcuts_arrow_vertical_offset); @@ -159,7 +144,7 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset); // Add the arrow. - mArrow = addArrowView(mArrowHorizontalOffset, arrowVerticalOffset, arrowWidth, arrowHeight); + mArrow = addArrowView(arrowHorizontalOffset, arrowVerticalOffset, arrowWidth, arrowHeight); mArrow.setPivotX(arrowWidth / 2); mArrow.setPivotY(mIsAboveIcon ? 0 : arrowHeight); @@ -347,7 +332,6 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC mIsAboveIcon = y > dragLayer.getTop() + insets.top; if (!mIsAboveIcon) { y = mTempRect.top + icon.getPaddingTop() + iconHeight; - icon.setTextVisibility(false); } // Insets are added later, so subtract them now. @@ -393,7 +377,6 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC private void deferDrag(BubbleTextView originalIcon) { mDeferredDragIcon = originalIcon; - showDragView(originalIcon); mLauncher.getDragController().addDragListener(this); } @@ -401,103 +384,39 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC return mDeferredDragIcon; } - private void showDragView(BubbleTextView originalIcon) { - // TODO: implement support for Drawable DragViews so we don't have to create a bitmap here. - Bitmap b = Utilities.createIconBitmap(originalIcon.getIcon(), mLauncher); - float scale = mLauncher.getDragLayer().getLocationInDragLayer(originalIcon, mTempXY); - int dragLayerX = Math.round(mTempXY[0] - (b.getWidth() - scale * originalIcon.getWidth()) / 2); - int dragLayerY = Math.round(mTempXY[1] - (b.getHeight() - scale * b.getHeight()) / 2 - - Workspace.DRAG_BITMAP_PADDING / 2) + originalIcon.getPaddingTop(); - int motionDownX = mLauncher.getDragController().getMotionDown().x; - int motionDownY = mLauncher.getDragController().getMotionDown().y; - final int registrationX = motionDownX - dragLayerX; - final int registrationY = motionDownY - dragLayerY; - - float scaleDps = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_drag_view_scale); - mDragView = new DragView(mLauncher, b, registrationX, registrationY, 1f, scaleDps); - mLastX = mLastY = mDistanceDragged = 0; - mDragView.show(motionDownX, motionDownY); - } - - public boolean onForwardedEvent(MotionEvent ev, int activePointerId, int[] touchDown) { - mActivePointerId = activePointerId; - mTouchDown = touchDown; - return dispatchTouchEvent(ev); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (mDeferredDragIcon == null) { - return false; - } - - final int activePointerIndex = ev.findPointerIndex(mActivePointerId); - if (activePointerIndex < 0) { - return false; - } - final float x = ev.getX(activePointerIndex); - final float y = ev.getY(activePointerIndex); - - - int action = ev.getAction(); - // The event was in this container's coordinate system before this, - // but will be in DragLayer's coordinate system from now on. - Utilities.translateEventCoordinates(this, mLauncher.getDragLayer(), ev); - final int dragLayerX = (int) ev.getX(); - final int dragLayerY = (int) ev.getY(); - if (action == MotionEvent.ACTION_MOVE) { - if (mLastX != 0 || mLastY != 0) { - mDistanceDragged += Math.hypot(mLastX - x, mLastY - y); - } - mLastX = x; - mLastY = y; - - 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 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); - mLauncher.getUserEventDispatcher().logDeepShortcutsOpen(mDeferredDragIcon); - } else if (action == MotionEvent.ACTION_CANCEL) { - // Do not change the source icon visibility if we are already dragging the source icon. - cleanupDeferredDrag(!mSrcIconDragStarted); - } - return true; - } - /** - * Determines whether the deferred drag should be started based on touch coordinates - * relative to the original icon and the shortcuts container. + * Determines when the deferred drag should be started. * * Current behavior: * - 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) { - double distFromTouchDown = Math.hypot(x - mTouchDown[0], y - mTouchDown[1]); - return distFromTouchDown > mStartDragThreshold; - } + public DragOptions.DeferDragCondition createDeferDragCondition(final Runnable onDragStart) { + return new DragOptions.DeferDragCondition() { + @Override + public boolean shouldStartDeferredDrag(double distanceDragged) { + return distanceDragged > mStartDragThreshold; + } - private void cleanupDeferredDrag(boolean updateSrcVisibility) { - if (mDragView != null) { - mDragView.remove(); - } - if (updateSrcVisibility) { - mDeferredDragIcon.setVisibility(VISIBLE); - } + @Override + public void onDeferredDragStart() { + mDeferredDragIcon.setVisibility(INVISIBLE); + } + + @Override + public void onDropBeforeDeferredDrag() { + mLauncher.getUserEventDispatcher().logDeepShortcutsOpen(mDeferredDragIcon); + if (!mIsAboveIcon) { + mDeferredDragIcon.setTextVisibility(false); + } + } + + @Override + public void onDragStart() { + if (onDragStart != null) { + onDragStart.run(); + } + } + }; } @Override @@ -581,9 +500,7 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC @Override public void onDragEnd() { - if (mIsOpen) { - animateClose(); - } else { + if (!mIsOpen) { if (mOpenCloseAnimator != null) { // Close animation is running. mDeferContainerRemoval = false; @@ -594,6 +511,7 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC } } } + mDeferredDragIcon.setVisibility(VISIBLE); } @Override @@ -701,8 +619,6 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC } mIsOpen = false; mDeferContainerRemoval = false; - // Make the original icon visible in All Apps, but not in Workspace or Folders. - cleanupDeferredDrag(mDeferredDragIcon.getTag() instanceof AppInfo); boolean isInHotseat = ((ItemInfo) mDeferredDragIcon.getTag()).container == LauncherSettings.Favorites.CONTAINER_HOTSEAT; mDeferredDragIcon.setTextVisibility(!isInHotseat); @@ -734,8 +650,6 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC container.setVisibility(View.INVISIBLE); launcher.getDragLayer().addView(container); container.populateAndShow(icon, ids); - icon.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); return container; } return null; diff --git a/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java b/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java deleted file mode 100644 index 31f096990..000000000 --- a/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java +++ /dev/null @@ -1,252 +0,0 @@ -package com.android.launcher3.shortcuts; - -import android.os.SystemClock; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; - -import com.android.launcher3.BubbleTextView; -import com.android.launcher3.CheckLongPressHelper; -import com.android.launcher3.Launcher; -import com.android.launcher3.Utilities; -import com.android.launcher3.dragndrop.DragLayer; - -/** - * A {@link android.view.View.OnTouchListener} that creates a {@link DeepShortcutsContainer} and - * forwards touch events to it. This listener should be put on any icon that supports shortcuts. - */ -public class ShortcutsContainerListener implements View.OnTouchListener, - View.OnAttachStateChangeListener { - - /** Scaled touch slop, used for detecting movement outside bounds. */ - private final float mScaledTouchSlop; - - /** Timeout before accepting a long-press to start forwarding. */ - private final int mLongPressTimeout; - - /** Source view from which events are forwarded. */ - private final BubbleTextView mSrcIcon; - - /** Runnable used to trigger forwarding on long-press. */ - private Runnable mTriggerLongPress; - - /** Whether this listener is currently forwarding touch events. */ - private boolean mForwarding; - - /** The id of the first pointer down in the current event stream. */ - private int mActivePointerId; - - private Launcher mLauncher; - private DragLayer mDragLayer; - /** The coordinates of the touch down, relative to the shortcuts container. */ - private final int[] mTouchDown; - private boolean mHasMappedTouchDownToContainerCoord; - - /** If true, the gesture is not handled. The value is reset when next gesture starts. */ - private boolean mIgnoreCurrentGesture; - private DeepShortcutsContainer mShortcutsContainer; - - public ShortcutsContainerListener(BubbleTextView icon) { - mSrcIcon = icon; - mScaledTouchSlop = ViewConfiguration.get(icon.getContext()).getScaledTouchSlop(); - - mLongPressTimeout = CheckLongPressHelper.DEFAULT_LONG_PRESS_TIMEOUT; - - icon.addOnAttachStateChangeListener(this); - - mLauncher = Launcher.getLauncher(mSrcIcon.getContext()); - mDragLayer = mLauncher.getDragLayer(); - mTouchDown = new int[2]; - } - - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - // There are no shortcuts associated with this item, - // so return to normal touch handling. - mIgnoreCurrentGesture = !mSrcIcon.hasDeepShortcuts(); - - mTouchDown[0] = (int) event.getX(); - mTouchDown[1] = (int) event.getY(); - mDragLayer.getDescendantCoordRelativeToSelf(mSrcIcon, mTouchDown); - mHasMappedTouchDownToContainerCoord = false; - } - - if (mIgnoreCurrentGesture) { - return false; - } - - final boolean wasForwarding = mForwarding; - final boolean forwarding; - if (wasForwarding) { - forwarding = onTouchForwarded(event) || !onForwardingStopped(); - } else { - forwarding = onTouchObserved(event) && onForwardingStarted(); - - if (forwarding) { - // Make sure we cancel any ongoing source event stream. - final long now = SystemClock.uptimeMillis(); - final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, - 0.0f, 0.0f, 0); - mSrcIcon.onTouchEvent(e); - e.recycle(); - } - } - - mForwarding = forwarding; - return forwarding || wasForwarding; - } - - @Override - public void onViewAttachedToWindow(View v) { - } - - @Override - public void onViewDetachedFromWindow(View v) { - mForwarding = false; - mActivePointerId = MotionEvent.INVALID_POINTER_ID; - } - - /** - * Called when forwarding would like to start. - * <p> - * This is when we populate the shortcuts container and add it to the DragLayer. - * - * @return true to start forwarding, false otherwise - */ - protected boolean onForwardingStarted() { - mShortcutsContainer = DeepShortcutsContainer.showForIcon(mSrcIcon); - return mShortcutsContainer != null; - } - - /** - * Called when forwarding would like to stop. - * - * @return true to stop forwarding, false otherwise - */ - protected boolean onForwardingStopped() { - mShortcutsContainer = null; - return true; - } - - /** - * Observes motion events and determines when to start forwarding. - * - * @param srcEvent motion event in source view coordinates - * @return true to start forwarding motion events, false otherwise - */ - private boolean onTouchObserved(MotionEvent srcEvent) { - final View src = mSrcIcon; - if (!src.isEnabled()) { - return false; - } - - final int actionMasked = srcEvent.getActionMasked(); - switch (actionMasked) { - case MotionEvent.ACTION_DOWN: - mActivePointerId = srcEvent.getPointerId(0); - - if (mTriggerLongPress == null) { - mTriggerLongPress = new TriggerLongPress(); - } - src.postDelayed(mTriggerLongPress, mLongPressTimeout); - break; - case MotionEvent.ACTION_MOVE: - final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId); - if (activePointerIndex >= 0) { - final float x = srcEvent.getX(activePointerIndex); - final float y = srcEvent.getY(activePointerIndex); - - // Has the pointer moved outside of the view? - if (!Utilities.pointInView(src, x, y, mScaledTouchSlop)) { - clearCallbacks(); - - return false; - } - } - break; - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - clearCallbacks(); - break; - } - - return false; - } - - private void clearCallbacks() { - if (mTriggerLongPress != null) { - mSrcIcon.removeCallbacks(mTriggerLongPress); - } - } - - private void onLongPress() { - clearCallbacks(); - - final BubbleTextView src = mSrcIcon; - if (!src.isEnabled() || !src.hasDeepShortcuts()) { - // Ignore long-press if the view is disabled or doesn't have shortcuts. - return; - } - - if (!onForwardingStarted()) { - return; - } - - // Don't let the parent intercept our events. - src.getParent().requestDisallowInterceptTouchEvent(true); - - // Make sure we cancel any ongoing source event stream. - final long now = SystemClock.uptimeMillis(); - final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0); - src.onTouchEvent(e); - e.recycle(); - - mForwarding = true; - } - - /** - * Handles forwarded motion events and determines when to stop - * forwarding. - * - * @param srcEvent motion event in source view coordinates - * @return true to continue forwarding motion events, false to cancel - */ - private boolean onTouchForwarded(MotionEvent srcEvent) { - final View src = mSrcIcon; - final DeepShortcutsContainer dst = mShortcutsContainer; - if (dst == null) { - return false; - } - // Always cancel forwarding when the touch stream ends. - final int action = srcEvent.getActionMasked(); - final boolean keepForwarding = action != MotionEvent.ACTION_UP - && action != MotionEvent.ACTION_CANCEL; - if (!dst.isLaidOut()) { - return keepForwarding; - } - - // Convert event to destination-local coordinates. - final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent); - Utilities.translateEventCoordinates(src, dst, dstEvent); - - // Convert touch down event to destination-local coordinates. - if (!mHasMappedTouchDownToContainerCoord) { - mDragLayer.mapCoordInSelfToDescendent(dst, mTouchDown); - mHasMappedTouchDownToContainerCoord = true; - } - - // Forward converted event to destination view, then recycle it. - final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId, mTouchDown); - dstEvent.recycle(); - - return handled && keepForwarding; - } - - private class TriggerLongPress implements Runnable { - @Override - public void run() { - onLongPress(); - } - } -} |