From c7cbf254f3b8e163488138305bd53f5fa075cceb Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 24 May 2021 15:46:48 -0700 Subject: [PATCH 1/2] Let DragView use ActivityContext instead of Launcher - Make DragView abstract and extended by LauncherDragView for the explicitly Launcher-specific parts. - Some other methods like Utilities.getFullDrawable() now accept (Activity)Context rather than Launcher. Test: Compiles and runs, manual drag and drop Bug: 182981908 Change-Id: I77b7a2e48ce864dd711c3232217fdba4d60c546f --- src/com/android/launcher3/Launcher.java | 3 +- src/com/android/launcher3/Utilities.java | 30 ++++---- .../android/launcher3/dragndrop/DragView.java | 72 +++++++------------ .../dragndrop/FolderAdaptiveIcon.java | 6 +- .../dragndrop/LauncherDragController.java | 4 +- .../launcher3/dragndrop/LauncherDragView.java | 70 ++++++++++++++++++ .../graphics/DragPreviewProvider.java | 8 +-- .../launcher3/views/ActivityContext.java | 10 +++ 8 files changed, 131 insertions(+), 72 deletions(-) create mode 100644 src/com/android/launcher3/dragndrop/LauncherDragView.java diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 4a7937bd2c..892fb6d6f0 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1289,7 +1289,8 @@ public class Launcher extends StatefulActivity implements Launche } } - public FolderIcon findFolderIcon(final int folderIconId) { + @Override + public @Nullable FolderIcon findFolderIcon(final int folderIconId) { return (FolderIcon) mWorkspace.getHomescreenIconByItemId(folderIconId); } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index cb9e1f3a5c..becbb27fb9 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -85,6 +85,7 @@ import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.PackageManagerHelper; +import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.widget.PendingAddShortcutInfo; @@ -651,25 +652,26 @@ public final class Utilities { * @param outObj this is set to the internal data associated with {@param info}, * eg {@link LauncherActivityInfo} or {@link ShortcutInfo}. */ - public static Drawable getFullDrawable(Launcher launcher, ItemInfo info, int width, int height, + public static Drawable getFullDrawable(Context context, ItemInfo info, int width, int height, Object[] outObj) { - Drawable icon = loadFullDrawableWithoutTheme(launcher, info, width, height, outObj); + Drawable icon = loadFullDrawableWithoutTheme(context, info, width, height, outObj); if (icon instanceof BitmapInfo.Extender) { - icon = ((BitmapInfo.Extender) icon).getThemedDrawable(launcher); + icon = ((BitmapInfo.Extender) icon).getThemedDrawable(context); } return icon; } - private static Drawable loadFullDrawableWithoutTheme(Launcher launcher, ItemInfo info, + private static Drawable loadFullDrawableWithoutTheme(Context context, ItemInfo info, int width, int height, Object[] outObj) { - LauncherAppState appState = LauncherAppState.getInstance(launcher); + ActivityContext activity = ActivityContext.lookupContext(context); + LauncherAppState appState = LauncherAppState.getInstance(context); if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { - LauncherActivityInfo activityInfo = launcher.getSystemService(LauncherApps.class) + LauncherActivityInfo activityInfo = context.getSystemService(LauncherApps.class) .resolveActivity(info.getIntent(), info.user); outObj[0] = activityInfo; - return activityInfo == null ? null : LauncherAppState.getInstance(launcher) + return activityInfo == null ? null : LauncherAppState.getInstance(context) .getIconProvider().getIcon( - activityInfo, launcher.getDeviceProfile().inv.fillResIconDpi); + activityInfo, activity.getDeviceProfile().inv.fillResIconDpi); } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { if (info instanceof PendingAddShortcutInfo) { ShortcutConfigActivityInfo activityInfo = @@ -678,18 +680,18 @@ public final class Utilities { return activityInfo.getFullResIcon(appState.getIconCache()); } List si = ShortcutKey.fromItemInfo(info) - .buildRequest(launcher) + .buildRequest(context) .query(ShortcutRequest.ALL); if (si.isEmpty()) { return null; } else { outObj[0] = si.get(0); - return ShortcutCachingLogic.getIcon(launcher, si.get(0), + return ShortcutCachingLogic.getIcon(context, si.get(0), appState.getInvariantDeviceProfile().fillResIconDpi); } } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { FolderAdaptiveIcon icon = FolderAdaptiveIcon.createFolderAdaptiveIcon( - launcher, info.id, new Point(width, height)); + activity, info.id, new Point(width, height)); if (icon == null) { return null; } @@ -707,8 +709,8 @@ public final class Utilities { * badge. When dragged from workspace or folder, it may contain app AND/OR work profile badge **/ @TargetApi(Build.VERSION_CODES.O) - public static Drawable getBadge(Launcher launcher, ItemInfo info, Object obj) { - LauncherAppState appState = LauncherAppState.getInstance(launcher); + public static Drawable getBadge(Context context, ItemInfo info, Object obj) { + LauncherAppState appState = LauncherAppState.getInstance(context); int iconSize = appState.getInvariantDeviceProfile().iconBitmapSize; if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { boolean iconBadged = (info instanceof ItemInfoWithIcon) @@ -728,7 +730,7 @@ public final class Utilities { } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { return ((FolderAdaptiveIcon) obj).getBadge(); } else { - return launcher.getPackageManager() + return context.getPackageManager() .getUserBadgedIcon(new FixedSizeEmptyDrawable(iconSize), info.user); } } diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java index 1664980c35..fb1a6bef18 100644 --- a/src/com/android/launcher3/dragndrop/DragView.java +++ b/src/com/android/launcher3/dragndrop/DragView.java @@ -53,22 +53,19 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.util.RunnableList; -import com.android.launcher3.util.Thunk; +import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; /** A custom view for rendering an icon, folder, shortcut or widget during drag-n-drop. */ -public class DragView extends FrameLayout implements StateListener { +public abstract class DragView extends FrameLayout { public static final int VIEW_ZOOM_DURATION = 150; @@ -81,19 +78,18 @@ public class DragView extends FrameLayout implements StateListener mDragLayer; private boolean mHasDrawn = false; final ValueAnimator mAnim; @@ -109,7 +105,7 @@ public class DragView extends FrameLayout implements StateListener * The registration point is the point inside our view that the touch events should * be centered upon. - * @param launcher The Launcher instance + * @param activity The Launcher instance/ActivityContext this DragView is in. * @param content the view content that is attached to the drag view. * @param width the width of the dragView * @param height the height of the dragView @@ -132,13 +128,12 @@ public class DragView extends FrameLayout implements StateListener { - FolderIcon icon = launcher.findFolderIcon(folderId); + FolderIcon icon = activity.findFolderIcon(folderId); return icon == null ? null : createDrawableOnUiThread(icon, dragViewSize); }).get(); diff --git a/src/com/android/launcher3/dragndrop/LauncherDragController.java b/src/com/android/launcher3/dragndrop/LauncherDragController.java index a98d70ce71..0e8b0a5ba6 100644 --- a/src/com/android/launcher3/dragndrop/LauncherDragController.java +++ b/src/com/android/launcher3/dragndrop/LauncherDragController.java @@ -96,7 +96,7 @@ public class LauncherDragController extends DragController { final float scaleDps = mIsInPreDrag ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f; final DragView dragView = mDragObject.dragView = drawable != null - ? new DragView( + ? new LauncherDragView( mActivity, drawable, registrationX, @@ -104,7 +104,7 @@ public class LauncherDragController extends DragController { initialDragViewScale, dragViewScaleOnDrop, scaleDps) - : new DragView( + : new LauncherDragView( mActivity, view, view.getMeasuredWidth(), diff --git a/src/com/android/launcher3/dragndrop/LauncherDragView.java b/src/com/android/launcher3/dragndrop/LauncherDragView.java new file mode 100644 index 0000000000..cc68e2e3e4 --- /dev/null +++ b/src/com/android/launcher3/dragndrop/LauncherDragView.java @@ -0,0 +1,70 @@ +/* + * 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.launcher3.dragndrop; + +import android.graphics.drawable.Drawable; +import android.view.View; + +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherState; +import com.android.launcher3.statemanager.StateManager; + +/** + * A DragView drawn/used by the Launcher activity. + */ +public class LauncherDragView extends DragView + implements StateManager.StateListener { + + + public LauncherDragView(Launcher launcher, Drawable drawable, int registrationX, + int registrationY, float initialScale, float scaleOnDrop, float finalScaleDps) { + super(launcher, drawable, registrationX, registrationY, initialScale, scaleOnDrop, + finalScaleDps); + } + + public LauncherDragView(Launcher launcher, View content, int width, int height, + int registrationX, int registrationY, float initialScale, float scaleOnDrop, + float finalScaleDps) { + super(launcher, content, width, height, registrationX, registrationY, initialScale, + scaleOnDrop, finalScaleDps); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mActivity.getStateManager().addStateListener(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mActivity.getStateManager().removeStateListener(this); + } + + @Override + public void onStateTransitionComplete(LauncherState finalState) { + setVisibility((finalState == LauncherState.NORMAL + || finalState == LauncherState.SPRING_LOADED) ? VISIBLE : INVISIBLE); + } + + @Override + public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) { + mTempLoc[0] = toTouchX - mRegistrationX; + mTempLoc[1] = toTouchY - mRegistrationY; + mActivity.getDragLayer().animateViewIntoPosition(this, mTempLoc, 1f, mScaleOnDrop, + mScaleOnDrop, DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration); + } +} diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java index a549750dae..f027b33f22 100644 --- a/src/com/android/launcher3/graphics/DragPreviewProvider.java +++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java @@ -32,13 +32,13 @@ import android.view.View; import androidx.annotation.Nullable; import com.android.launcher3.BubbleTextView; -import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.icons.BitmapRenderer; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.util.SafeCloseable; +import com.android.launcher3.views.ActivityContext; import com.android.launcher3.widget.LauncherAppWidgetHostView; import java.nio.ByteBuffer; @@ -150,7 +150,7 @@ public class DragPreviewProvider { } public float getScaleAndPosition(Drawable preview, int[] outPos) { - float scale = Launcher.getLauncher(mView.getContext()) + float scale = ActivityContext.lookupContext(mView.getContext()) .getDragLayer().getLocationInDragLayer(mView, outPos); if (mView instanceof LauncherAppWidgetHostView) { // App widgets are technically scaled, but are drawn at their expected size -- so the @@ -167,7 +167,7 @@ public class DragPreviewProvider { /** Returns the scale and position of a given view for drag-n-drop. */ public float getScaleAndPosition(View view, int[] outPos) { - float scale = Launcher.getLauncher(mView.getContext()) + float scale = ActivityContext.lookupContext(mView.getContext()) .getDragLayer().getLocationInDragLayer(mView, outPos); if (mView instanceof LauncherAppWidgetHostView) { // App widgets are technically scaled, but are drawn at their expected size -- so the @@ -201,7 +201,7 @@ public class DragPreviewProvider { public void run() { Bitmap preview = convertPreviewToAlphaBitmap(mPreviewSnapshot); if (mIsIcon) { - int size = Launcher.getLauncher(mContext).getDeviceProfile().iconSizePx; + int size = ActivityContext.lookupContext(mContext).getDeviceProfile().iconSizePx; preview = Bitmap.createScaledBitmap(preview, size, size, false); } //else case covers AppWidgetHost (doesn't drag/drop across different device profiles) diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index 646b66942c..b95904eba9 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -21,9 +21,12 @@ import android.graphics.Rect; import android.view.LayoutInflater; import android.view.View.AccessibilityDelegate; +import androidx.annotation.Nullable; + import com.android.launcher3.DeviceProfile; import com.android.launcher3.dot.DotInfo; import com.android.launcher3.dragndrop.DragController; +import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.ViewCache; @@ -99,6 +102,13 @@ public interface ActivityContext { return null; } + /** + * Returns the FolderIcon with the given item id, if it exists. + */ + default @Nullable FolderIcon findFolderIcon(final int folderIconId) { + return null; + } + /** * Returns the ActivityContext associated with the given Context. */ From 8ac277ebd8bc9e10a8b5d09c2b974abb065c5ec9 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 24 May 2021 15:47:38 -0700 Subject: [PATCH 2/2] Taskbar drag starts internal pre-drag before system drag - TaskbarDragController now extends DragController. - Currently there is no pre-drag condition, so we immediately get onDragStart(), which starts the system global drag (which cancels the original internal drag). - Make the original view invisible during the drag and drop operation, across both internal and system drag events. - No longer handle onDragEvent() in TaskbarView, as TaskbarDragController handles all of it now. Test: Drag and drop from taskbar still works (bonus: starts from the correct registration point that you touched down on). Locally added a PreDragCondition and verified a seamless handoff to system drag and drop when the pre drag end condition was met. Bug: 182981908 Change-Id: I6bf48141a5eedfc6db6f461258e880ef8146e733 --- .../taskbar/LauncherTaskbarUIController.java | 2 +- .../taskbar/TaskbarActivityContext.java | 85 +++--- .../taskbar/TaskbarDragController.java | 261 ++++++++++++++++-- .../launcher3/taskbar/TaskbarDragLayer.java | 7 +- .../launcher3/taskbar/TaskbarDragView.java | 56 ++++ .../taskbar/TaskbarIconController.java | 19 +- .../launcher3/taskbar/TaskbarView.java | 33 +-- src/com/android/launcher3/BubbleTextView.java | 5 +- .../launcher3/dragndrop/DragController.java | 16 +- .../launcher3/dragndrop/DragDriver.java | 15 +- 10 files changed, 381 insertions(+), 118 deletions(-) create mode 100644 quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index c2d107c22d..ee57dd9fe0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -222,7 +222,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } public boolean isDraggingItem() { - return mTaskbarView.isDraggingItem(); + return mContext.getDragController().isDragging(); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 8c3d453b09..98b01b0a8c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -28,9 +28,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.graphics.PixelFormat; -import android.graphics.Point; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.os.Process; import android.os.SystemProperties; import android.util.Log; @@ -43,22 +41,14 @@ import android.view.WindowManager; import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.DragSource; -import com.android.launcher3.DropTarget; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; -import com.android.launcher3.dragndrop.DragController; -import com.android.launcher3.dragndrop.DragOptions; -import com.android.launcher3.dragndrop.DragView; -import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.model.data.FolderInfo; -import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton; import com.android.launcher3.touch.ItemClickHandler; @@ -89,10 +79,13 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ private final LayoutInflater mLayoutInflater; private final TaskbarDragLayer mDragLayer; private final TaskbarIconController mIconController; - private final MyDragController mDragController; + private final TaskbarDragController mDragController; private final WindowManager mWindowManager; private WindowManager.LayoutParams mWindowLayoutParams; + private boolean mIsFullscreen; + // The size we should return to when we call setTaskbarWindowFullscreen(false) + private int mLastRequestedNonFullscreenHeight; private final SysUINavigationMode.Mode mNavMode; private final TaskbarNavButtonController mNavButtonController; @@ -114,8 +107,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode", () -> getPackageManager().isSafeMode()); - mOnTaskbarIconLongClickListener = - new TaskbarDragController(this)::startSystemDragOnLongClick; + mDragController = new TaskbarDragController(this); + mOnTaskbarIconLongClickListener = mDragController::startDragOnLongClick; mOnTaskbarIconClickListener = this::onTaskbarIconClicked; float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size); @@ -126,7 +119,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ mDragLayer = (TaskbarDragLayer) mLayoutInflater .inflate(R.layout.taskbar, null, false); mIconController = new TaskbarIconController(this, mDragLayer); - mDragController = new MyDragController(this); Display display = windowContext.getDisplay(); Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY @@ -136,9 +128,10 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ } public void init() { + mLastRequestedNonFullscreenHeight = mDeviceProfile.taskbarSize; mWindowLayoutParams = new WindowManager.LayoutParams( MATCH_PARENT, - mDeviceProfile.taskbarSize, + mLastRequestedNonFullscreenHeight, TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); @@ -160,17 +153,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ mWindowManager.addView(mDragLayer, mWindowLayoutParams); } - /** - * Updates the TaskbarContainer height (pass deviceProfile.taskbarSize to reset). - */ - public void setTaskbarWindowHeight(int height) { - if (mWindowLayoutParams.height == height) { - return; - } - mWindowLayoutParams.height = height; - mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams); - } - public boolean canShowNavButtons() { return ENABLE_THREE_BUTTON_TASKBAR && mNavMode == Mode.THREE_BUTTONS; } @@ -196,7 +178,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ } @Override - public DragController getDragController() { + public TaskbarDragController getDragController() { return mDragController; } @@ -243,8 +225,30 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ /** * Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size. */ - protected void setTaskbarWindowFullscreen(boolean fullscreen) { - setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : getDeviceProfile().taskbarSize); + public void setTaskbarWindowFullscreen(boolean fullscreen) { + mIsFullscreen = fullscreen; + setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight); + } + + /** + * Updates the TaskbarContainer height (pass deviceProfile.taskbarSize to reset). + */ + public void setTaskbarWindowHeight(int height) { + if (mWindowLayoutParams.height == height) { + return; + } + if (height != MATCH_PARENT) { + mLastRequestedNonFullscreenHeight = height; + if (mIsFullscreen) { + // We still need to be fullscreen, so defer any change to our height until we call + // setTaskbarWindowFullscreen(false). For example, this could happen when dragging + // from the gesture region, as the drag will cancel the gesture and reset launcher's + // state, which in turn normally would reset the taskbar window height as well. + return; + } + } + mWindowLayoutParams.height = height; + mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams); } protected void onTaskbarIconClicked(View view) { @@ -309,27 +313,4 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ AbstractFloatingView.closeAllOpenViews(this); } - - private static class MyDragController extends DragController { - MyDragController(TaskbarActivityContext activity) { - super(activity); - } - - @Override - protected DragView startDrag(@Nullable 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) { - return null; - } - - @Override - protected void exitDrag() { - } - - @Override - protected DropTarget getDefaultDropTarget(int[] dropCoordinates) { - return null; - } - } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index ee44927ce4..855c50728b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -20,19 +20,35 @@ import static android.view.View.VISIBLE; import android.content.ClipData; import android.content.ClipDescription; -import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.view.DragEvent; +import android.view.MotionEvent; import android.view.View; +import androidx.annotation.Nullable; + +import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; +import com.android.launcher3.DragSource; +import com.android.launcher3.DropTarget; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; +import com.android.launcher3.accessibility.DragViewStateAnnouncer; +import com.android.launcher3.dragndrop.DragController; +import com.android.launcher3.dragndrop.DragDriver; +import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.dragndrop.DragView; +import com.android.launcher3.dragndrop.DraggableView; +import com.android.launcher3.graphics.DragPreviewProvider; +import com.android.launcher3.icons.FastBitmapDrawable; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ClipDescriptionCompat; @@ -41,14 +57,20 @@ import com.android.systemui.shared.system.LauncherAppsCompat; /** * Handles long click on Taskbar items to start a system drag and drop operation. */ -public class TaskbarDragController { +public class TaskbarDragController extends DragController { - private final Context mContext; private final int mDragIconSize; + private final int[] mTempXY = new int[2]; - public TaskbarDragController(Context context) { - mContext = context; - Resources resources = mContext.getResources(); + // Where the initial touch was relative to the dragged icon. + private int mRegistrationX; + private int mRegistrationY; + + private boolean mIsSystemDragInProgress; + + public TaskbarDragController(TaskbarActivityContext activity) { + super(activity); + Resources resources = mActivity.getResources(); mDragIconSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_drag_icon_size); } @@ -57,18 +79,146 @@ public class TaskbarDragController { * generate the ClipDescription and Intent. * @return Whether {@link View#startDragAndDrop} started successfully. */ - protected boolean startSystemDragOnLongClick(View view) { + protected boolean startDragOnLongClick(View view) { if (!(view instanceof BubbleTextView)) { return false; } BubbleTextView btv = (BubbleTextView) view; - View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view) { + + mActivity.setTaskbarWindowFullscreen(true); + view.post(() -> { + startInternalDrag(btv); + btv.setVisibility(INVISIBLE); + }); + return true; + } + + private void startInternalDrag(BubbleTextView btv) { + float iconScale = 1f; + Drawable icon = btv.getIcon(); + if (icon instanceof FastBitmapDrawable) { + iconScale = ((FastBitmapDrawable) icon).getAnimatedScale(); + } + + // Clear the pressed state if necessary + btv.clearFocus(); + btv.setPressed(false); + btv.clearPressedBackground(); + + final DragPreviewProvider previewProvider = new DragPreviewProvider(btv); + final Drawable drawable = previewProvider.createDrawable(); + final float scale = previewProvider.getScaleAndPosition(drawable, mTempXY); + int dragLayerX = mTempXY[0]; + int dragLayerY = mTempXY[1]; + + Rect dragRect = new Rect(); + btv.getSourceVisualDragBounds(dragRect); + dragLayerY += dragRect.top; + + DragOptions dragOptions = new DragOptions(); + // TODO: open popup/pre-drag + // PopupContainerWithArrow popupContainer = PopupContainerWithArrow.showForIcon(view); + // if (popupContainer != null) { + // dragOptions.preDragCondition = popupContainer.createPreDragCondition(); + // } + + startDrag( + drawable, + /* view = */ null, + /* originalView = */ btv, + dragLayerX, + dragLayerY, + (View target, DropTarget.DragObject d, boolean success) -> {} /* DragSource */, + (WorkspaceItemInfo) btv.getTag(), + /* dragVisualizeOffset = */ null, + dragRect, + scale * iconScale, + scale, + dragOptions); + } + + @Override + protected DragView startDrag(@Nullable 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) { + mOptions = options; + + mRegistrationX = mMotionDown.x - dragLayerX; + mRegistrationY = mMotionDown.y - dragLayerY; + + final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left; + final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top; + + mLastDropTarget = null; + + mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext()); + mDragObject.originalView = originalView; + + mIsInPreDrag = mOptions.preDragCondition != null + && !mOptions.preDragCondition.shouldStartDrag(0); + + float scalePx = mDragIconSize - dragRegion.width(); + final DragView dragView = mDragObject.dragView = new TaskbarDragView( + mActivity, + drawable, + mRegistrationX, + mRegistrationY, + initialDragViewScale, + dragViewScaleOnDrop, + scalePx); + dragView.setItemInfo(dragInfo); + mDragObject.dragComplete = false; + + mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft); + mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop); + + mDragDriver = DragDriver.create(this, mOptions, /* secondaryEventConsumer = */ ev -> {}); + if (!mOptions.isAccessibleDrag) { + mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView); + } + + mDragObject.dragSource = source; + mDragObject.dragInfo = dragInfo; + mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy(); + + if (dragRegion != null) { + dragView.setDragRegion(new Rect(dragRegion)); + } + + dragView.show(mLastTouch.x, mLastTouch.y); + mDistanceSinceScroll = 0; + + if (!mIsInPreDrag) { + callOnDragStart(); + } else if (mOptions.preDragCondition != null) { + mOptions.preDragCondition.onPreDragStart(mDragObject); + } + + handleMoveEvent(mLastTouch.x, mLastTouch.y); + + return dragView; + } + + @Override + protected void callOnDragStart() { + super.callOnDragStart(); + // Pre-drag has ended, start the global system drag. + AbstractFloatingView.closeAllOpenViews(mActivity); + startSystemDrag((BubbleTextView) mDragObject.originalView); + } + + private void startSystemDrag(BubbleTextView btv) { + View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(btv) { + @Override public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) { shadowSize.set(mDragIconSize, mDragIconSize); - // TODO: should be based on last touch point on the icon. - shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2); + // The registration point was taken before the icon scaled to mDragIconSize, so + // offset the registration to where the touch is on the new size. + int offset = (mDragIconSize - btv.getIconSize()) / 2; + shadowTouchPoint.set(mRegistrationX + offset, mRegistrationY + offset); } @Override @@ -81,12 +231,12 @@ public class TaskbarDragController { } }; - Object tag = view.getTag(); + Object tag = btv.getTag(); ClipDescription clipDescription = null; Intent intent = null; if (tag instanceof WorkspaceItemInfo) { WorkspaceItemInfo item = (WorkspaceItemInfo) tag; - LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); + LauncherApps launcherApps = mActivity.getSystemService(LauncherApps.class); clipDescription = new ClipDescription(item.title, new String[] { item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT @@ -116,28 +266,89 @@ public class TaskbarDragController { if (clipDescription != null && intent != null) { ClipData clipData = new ClipData(clipDescription, new ClipData.Item(intent)); - view.setOnDragListener(getDraggedViewDragListener()); - return view.startDragAndDrop(clipData, shadowBuilder, null /* localState */, - View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE); + if (btv.startDragAndDrop(clipData, shadowBuilder, null /* localState */, + View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE)) { + onSystemDragStarted(); + } } - return false; } - /** - * Hide the original Taskbar item while it is being dragged. - */ - private View.OnDragListener getDraggedViewDragListener() { - return (view, dragEvent) -> { + private void onSystemDragStarted() { + mIsSystemDragInProgress = true; + mActivity.getDragLayer().setOnDragListener((view, dragEvent) -> { switch (dragEvent.getAction()) { case DragEvent.ACTION_DRAG_STARTED: - view.setVisibility(INVISIBLE); + // Return true to tell system we are interested in events, so we get DRAG_ENDED. return true; case DragEvent.ACTION_DRAG_ENDED: - view.setVisibility(VISIBLE); - view.setOnDragListener(null); + mIsSystemDragInProgress = false; + maybeOnDragEnd(); return true; } return false; - }; + }); + } + + @Override + public boolean isDragging() { + return super.isDragging() || mIsSystemDragInProgress; + } + + /** + * Whether we started dragging the given view and the drag is still in progress. + */ + public boolean isDraggingView(View child) { + return isDragging() && mDragObject != null && mDragObject.originalView == child; + } + + private void maybeOnDragEnd() { + if (!isDragging()) { + ((View) mDragObject.originalView).setVisibility(VISIBLE); + } + } + + @Override + protected void callOnDragEnd() { + super.callOnDragEnd(); + maybeOnDragEnd(); + } + + @Override + protected float getX(MotionEvent ev) { + // We will resize to fill the screen while dragging, so use screen coordinates. This ensures + // we start at the correct position even though touch down is on the smaller DragLayer size. + return ev.getRawX(); + } + + @Override + protected float getY(MotionEvent ev) { + // We will resize to fill the screen while dragging, so use screen coordinates. This ensures + // we start at the correct position even though touch down is on the smaller DragLayer size. + return ev.getRawY(); + } + + @Override + protected Point getClampedDragLayerPos(float x, float y) { + // No need to clamp, as we will take up the entire screen. + mTmpPoint.set(Math.round(x), Math.round(y)); + return mTmpPoint; + } + + @Override + protected void exitDrag() { + if (mDragObject != null) { + mActivity.getDragLayer().removeView(mDragObject.dragView); + } + } + + @Override + public void addDropTarget(DropTarget target) { + // No-op as Taskbar currently doesn't support any drop targets internally. + // Note: if we do add internal DropTargets, we'll still need to ignore Folder. + } + + @Override + protected DropTarget getDefaultDropTarget(int[] dropCoordinates) { + return null; } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java index 45ec911527..2469f95bfb 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java @@ -40,7 +40,7 @@ public class TaskbarDragLayer extends BaseDragLayer { private final int mFolderMargin; private final Paint mTaskbarBackgroundPaint; - private TaskbarIconController.Callbacks mControllerCallbacks; + private TaskbarIconController.TaskbarDragLayerCallbacks mControllerCallbacks; private TaskbarView mTaskbarView; private final OnComputeInsetsListener mTaskbarInsetsComputer = this::onComputeTaskbarInsets; @@ -69,10 +69,11 @@ public class TaskbarDragLayer extends BaseDragLayer { @Override public void recreateControllers() { - mControllers = new TouchController[0]; + mControllers = new TouchController[] {mActivity.getDragController()}; } - public void init(TaskbarIconController.Callbacks callbacks, TaskbarView taskbarView) { + public void init(TaskbarIconController.TaskbarDragLayerCallbacks callbacks, + TaskbarView taskbarView) { mControllerCallbacks = callbacks; mTaskbarView = taskbarView; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java new file mode 100644 index 0000000000..cf28eff0c2 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java @@ -0,0 +1,56 @@ +/* + * 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.launcher3.taskbar; + +import android.graphics.drawable.Drawable; + +import com.android.launcher3.R; +import com.android.launcher3.dragndrop.DragView; + +/** + * A DragView drawn/used by the Taskbar. Note that this is only for the internal drag-and-drop, + * while the pre-drag is still in progress (i.e. when the long press popup is still open). After + * that ends, we switch to a system drag and drop view instead. + */ +public class TaskbarDragView extends DragView { + public TaskbarDragView(TaskbarActivityContext launcher, Drawable drawable, int registrationX, + int registrationY, float initialScale, float scaleOnDrop, float finalScaleDps) { + super(launcher, drawable, registrationX, registrationY, initialScale, scaleOnDrop, + finalScaleDps); + } + + @Override + public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) { + Runnable onAnimationEnd = () -> { + if (onCompleteRunnable != null) { + onCompleteRunnable.run(); + } + mActivity.getDragLayer().removeView(this); + }; + + duration = Math.max(duration, + getResources().getInteger(R.integer.config_dropAnimMinDuration)); + + animate() + .translationX(toTouchX - mRegistrationX) + .translationY(toTouchY - mRegistrationY) + .scaleX(mScaleOnDrop) + .scaleY(mScaleOnDrop) + .withEndAction(onAnimationEnd) + .setDuration(duration) + .start(); + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java index 683a5b9fc4..cf0694ba60 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java @@ -62,10 +62,11 @@ public class TaskbarIconController { ButtonProvider buttonProvider = new ButtonProvider(mActivity); mImeBarView.init(buttonProvider); - mTaskbarView.construct(clickListener, longClickListener, buttonProvider); + mTaskbarView.init(new TaskbarViewCallbacks(), clickListener, longClickListener, + buttonProvider); mTaskbarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize; - mDragLayer.init(new Callbacks(), mTaskbarView); + mDragLayer.init(new TaskbarDragLayerCallbacks(), mTaskbarView); } public void onDestroy() { @@ -102,7 +103,7 @@ public class TaskbarIconController { /** * Callbacks for {@link TaskbarDragLayer} to interact with the icon controller */ - public class Callbacks { + public class TaskbarDragLayerCallbacks { /** * Called to update the touchable insets @@ -160,4 +161,16 @@ public class TaskbarIconController { mImeBarView.setVisibility(alpha == 0 ? GONE : VISIBLE); } } + + /** + * Callbacks for {@link TaskbarView} to interact with the icon controller + */ + public class TaskbarViewCallbacks { + /** + * Returns whether no other controller is currently handling the given View's visibility. + */ + public boolean canUpdateViewVisibility(View child) { + return !mActivity.getDragController().isDraggingView(child); + } + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index c6573a639c..ac7035876e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -24,7 +24,6 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; -import android.view.DragEvent; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -35,7 +34,6 @@ import androidx.annotation.LayoutRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.Insettable; import com.android.launcher3.R; @@ -62,7 +60,8 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa private final TaskbarActivityContext mActivityContext; - // Initialized in TaskbarController constructor. + // Initialized in init. + private TaskbarIconController.TaskbarViewCallbacks mControllerCallbacks; private View.OnClickListener mIconClickListener; private View.OnLongClickListener mIconLongClickListener; @@ -75,7 +74,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa // Prevents dispatching touches to children if true private boolean mTouchEnabled = true; - private boolean mIsDraggingItem; // Only non-null when the corresponding Folder is open. private @Nullable FolderIcon mLeaveBehindFolderIcon; @@ -118,8 +116,10 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa mHotseatIconsContainer = findViewById(R.id.hotseat_icons_layout); } - protected void construct(OnClickListener clickListener, OnLongClickListener longClickListener, - ButtonProvider buttonProvider) { + protected void init(TaskbarIconController.TaskbarViewCallbacks callbacks, + OnClickListener clickListener, OnLongClickListener longClickListener, + ButtonProvider buttonProvider) { + mControllerCallbacks = callbacks; mIconClickListener = clickListener; mIconLongClickListener = longClickListener; mButtonProvider = buttonProvider; @@ -225,6 +225,9 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } private void updateHotseatItemVisibility(View hotseatView) { + if (!mControllerCallbacks.canUpdateViewVisibility(hotseatView)) { + return; + } hotseatView.setVisibility( hotseatView.getTag() != null ? VISIBLE : (mAreHolesAllowed ? INVISIBLE : GONE)); } @@ -349,24 +352,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa mSystemButtonContainer.addView(mButtonProvider.getRecents(), buttonParams); } - @Override - public boolean onDragEvent(DragEvent event) { - switch (event.getAction()) { - case DragEvent.ACTION_DRAG_STARTED: - mIsDraggingItem = true; - AbstractFloatingView.closeAllOpenViews(mActivityContext); - return true; - case DragEvent.ACTION_DRAG_ENDED: - mIsDraggingItem = false; - break; - } - return super.onDragEvent(event); - } - - public boolean isDraggingItem() { - return mIsDraggingItem; - } - /** * @return The bounding box of where the hotseat elements are relative to this TaskbarView. */ diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 786678631f..150db1e191 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -413,7 +413,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, } } - void clearPressedBackground() { + public void clearPressedBackground() { setPressed(false); setStayPressed(false); } @@ -859,8 +859,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, switch (display) { case DISPLAY_ALL_APPS: return grid.allAppsIconSizePx; - case DISPLAY_WORKSPACE: case DISPLAY_FOLDER: + return grid.folderChildIconSizePx; + case DISPLAY_WORKSPACE: default: return grid.iconSizePx; } diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index 5731db4cbb..1e0edacfe8 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -74,7 +74,7 @@ public abstract class DragController /** Coordinate for last touch event **/ protected final Point mLastTouch = new Point(); - private final Point mTmpPoint = new Point(); + protected final Point mTmpPoint = new Point(); protected DropTarget.DragObject mDragObject; @@ -317,7 +317,7 @@ public abstract class DragController mDragObject.dragView.animateTo(mMotionDown.x, mMotionDown.y, onCompleteRunnable, duration); } - private void callOnDragEnd() { + protected void callOnDragEnd() { if (mIsInPreDrag && mOptions.preDragCondition != null) { mOptions.preDragCondition.onPreDragEnd(mDragObject, false /* dragStarted*/); } @@ -343,7 +343,7 @@ public abstract class DragController /** * Clamps the position to the drag layer bounds. */ - private Point getClampedDragLayerPos(float x, float y) { + protected Point getClampedDragLayerPos(float x, float y) { mActivity.getDragLayer().getLocalVisibleRect(mRectTemp); mTmpPoint.x = (int) Math.max(mRectTemp.left, Math.min(x, mRectTemp.right - 1)); mTmpPoint.y = (int) Math.max(mRectTemp.top, Math.min(y, mRectTemp.bottom - 1)); @@ -390,7 +390,7 @@ public abstract class DragController return false; } - Point dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY()); + Point dragLayerPos = getClampedDragLayerPos(getX(ev), getY(ev)); mLastTouch.set(dragLayerPos.x, dragLayerPos.y); if (ev.getAction() == MotionEvent.ACTION_DOWN) { // Remember location of down touch @@ -403,6 +403,14 @@ public abstract class DragController return mDragDriver != null && mDragDriver.onInterceptTouchEvent(ev); } + protected float getX(MotionEvent ev) { + return ev.getX(); + } + + protected float getY(MotionEvent ev) { + return ev.getY(); + } + /** * Call this from a drag source view. */ diff --git a/src/com/android/launcher3/dragndrop/DragDriver.java b/src/com/android/launcher3/dragndrop/DragDriver.java index d4ce3080c0..72e47e536c 100644 --- a/src/com/android/launcher3/dragndrop/DragDriver.java +++ b/src/com/android/launcher3/dragndrop/DragDriver.java @@ -165,8 +165,11 @@ public abstract class DragDriver { * Class for driving an internal (i.e. not using framework) drag/drop operation. */ static class InternalDragDriver extends DragDriver { + private final DragController mDragController; + InternalDragDriver(DragController dragController, Consumer sec) { super(dragController, sec); + mDragController = dragController; } @Override @@ -176,11 +179,14 @@ public abstract class DragDriver { switch (action) { case MotionEvent.ACTION_MOVE: - mEventListener.onDriverDragMove(ev.getX(), ev.getY()); + mEventListener.onDriverDragMove(mDragController.getX(ev), + mDragController.getY(ev)); break; case MotionEvent.ACTION_UP: - mEventListener.onDriverDragMove(ev.getX(), ev.getY()); - mEventListener.onDriverDragEnd(ev.getX(), ev.getY()); + mEventListener.onDriverDragMove(mDragController.getX(ev), + mDragController.getY(ev)); + mEventListener.onDriverDragEnd(mDragController.getX(ev), + mDragController.getY(ev)); break; case MotionEvent.ACTION_CANCEL: mEventListener.onDriverDragCancel(); @@ -197,7 +203,8 @@ public abstract class DragDriver { switch (action) { case MotionEvent.ACTION_UP: - mEventListener.onDriverDragEnd(ev.getX(), ev.getY()); + mEventListener.onDriverDragEnd(mDragController.getX(ev), + mDragController.getY(ev)); break; case MotionEvent.ACTION_CANCEL: mEventListener.onDriverDragCancel();