1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.launcher3.dragndrop; 17 18 import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE; 19 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; 20 import static com.android.launcher3.LauncherState.NORMAL; 21 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; 22 23 import android.content.res.Resources; 24 import android.graphics.Point; 25 import android.graphics.Rect; 26 import android.graphics.drawable.Drawable; 27 import android.util.Log; 28 import android.view.HapticFeedbackConstants; 29 import android.view.View; 30 31 import androidx.annotation.Nullable; 32 33 import com.android.launcher3.AbstractFloatingView; 34 import com.android.launcher3.DragSource; 35 import com.android.launcher3.DropTarget; 36 import com.android.launcher3.Launcher; 37 import com.android.launcher3.R; 38 import com.android.launcher3.accessibility.DragViewStateAnnouncer; 39 import com.android.launcher3.model.data.ItemInfo; 40 import com.android.launcher3.testing.TestProtocol; 41 42 /** 43 * Drag controller for Launcher activity 44 */ 45 public class LauncherDragController extends DragController<Launcher> { 46 47 private static final boolean PROFILE_DRAWING_DURING_DRAG = false; 48 49 private final FlingToDeleteHelper mFlingToDeleteHelper; 50 LauncherDragController(Launcher launcher)51 public LauncherDragController(Launcher launcher) { 52 super(launcher); 53 mFlingToDeleteHelper = new FlingToDeleteHelper(launcher); 54 } 55 56 @Override startDrag( @ullable Drawable drawable, @Nullable View view, DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source, ItemInfo dragInfo, Point dragOffset, Rect dragRegion, float initialDragViewScale, float dragViewScaleOnDrop, DragOptions options)57 protected DragView startDrag( 58 @Nullable Drawable drawable, 59 @Nullable View view, 60 DraggableView originalView, 61 int dragLayerX, 62 int dragLayerY, 63 DragSource source, 64 ItemInfo dragInfo, 65 Point dragOffset, 66 Rect dragRegion, 67 float initialDragViewScale, 68 float dragViewScaleOnDrop, 69 DragOptions options) { 70 if (TestProtocol.sDebugTracing) { 71 Log.d(TestProtocol.NO_DROP_TARGET, "5"); 72 } 73 if (PROFILE_DRAWING_DURING_DRAG) { 74 android.os.Debug.startMethodTracing("Launcher"); 75 } 76 77 mActivity.hideKeyboard(); 78 AbstractFloatingView.closeOpenViews(mActivity, false, TYPE_DISCOVERY_BOUNCE); 79 80 mOptions = options; 81 if (mOptions.simulatedDndStartPoint != null) { 82 mLastTouch.x = mMotionDown.x = mOptions.simulatedDndStartPoint.x; 83 mLastTouch.y = mMotionDown.y = mOptions.simulatedDndStartPoint.y; 84 } 85 86 final int registrationX = mMotionDown.x - dragLayerX; 87 final int registrationY = mMotionDown.y - dragLayerY; 88 89 final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left; 90 final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top; 91 92 mLastDropTarget = null; 93 94 mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext()); 95 mDragObject.originalView = originalView; 96 97 mIsInPreDrag = mOptions.preDragCondition != null 98 && !mOptions.preDragCondition.shouldStartDrag(0); 99 100 final Resources res = mActivity.getResources(); 101 final float scaleDps = mIsInPreDrag 102 ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f; 103 final DragView dragView = mDragObject.dragView = drawable != null 104 ? new LauncherDragView( 105 mActivity, 106 drawable, 107 registrationX, 108 registrationY, 109 initialDragViewScale, 110 dragViewScaleOnDrop, 111 scaleDps) 112 : new LauncherDragView( 113 mActivity, 114 view, 115 view.getMeasuredWidth(), 116 view.getMeasuredHeight(), 117 registrationX, 118 registrationY, 119 initialDragViewScale, 120 dragViewScaleOnDrop, 121 scaleDps); 122 dragView.setItemInfo(dragInfo); 123 mDragObject.dragComplete = false; 124 125 mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft); 126 mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop); 127 128 mDragDriver = DragDriver.create(this, mOptions, mFlingToDeleteHelper::recordMotionEvent); 129 if (!mOptions.isAccessibleDrag) { 130 mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView); 131 } 132 133 mDragObject.dragSource = source; 134 mDragObject.dragInfo = dragInfo; 135 mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy(); 136 137 if (dragOffset != null) { 138 dragView.setDragVisualizeOffset(new Point(dragOffset)); 139 } 140 if (dragRegion != null) { 141 dragView.setDragRegion(new Rect(dragRegion)); 142 } 143 144 mActivity.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 145 dragView.show(mLastTouch.x, mLastTouch.y); 146 mDistanceSinceScroll = 0; 147 148 if (!mIsInPreDrag) { 149 callOnDragStart(); 150 } else if (mOptions.preDragCondition != null) { 151 mOptions.preDragCondition.onPreDragStart(mDragObject); 152 } 153 154 handleMoveEvent(mLastTouch.x, mLastTouch.y); 155 156 if (!mActivity.isTouchInProgress() && options.simulatedDndStartPoint == null) { 157 // If it is an internal drag and the touch is already complete, cancel immediately 158 MAIN_EXECUTOR.submit(this::cancelDrag); 159 } 160 return dragView; 161 } 162 163 @Override exitDrag()164 protected void exitDrag() { 165 mActivity.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY); 166 } 167 168 @Override endWithFlingAnimation()169 protected boolean endWithFlingAnimation() { 170 Runnable flingAnimation = mFlingToDeleteHelper.getFlingAnimation(mDragObject, mOptions); 171 if (flingAnimation != null) { 172 drop(mFlingToDeleteHelper.getDropTarget(), flingAnimation); 173 return true; 174 } 175 return super.endWithFlingAnimation(); 176 } 177 178 @Override endDrag()179 protected void endDrag() { 180 super.endDrag(); 181 mFlingToDeleteHelper.releaseVelocityTracker(); 182 } 183 184 @Override getDefaultDropTarget(int[] dropCoordinates)185 protected DropTarget getDefaultDropTarget(int[] dropCoordinates) { 186 mActivity.getDragLayer().mapCoordInSelfToDescendant(mActivity.getWorkspace(), 187 dropCoordinates); 188 return mActivity.getWorkspace(); 189 } 190 } 191