From 027fba3527fbafe1d0a24136e91de6796961b866 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 19 Jun 2017 15:30:19 -0700 Subject: Refactoring PinItemDragListener into a base class to allow diffenret implementations of multi-window drag and drop Bug: 62702235 Change-Id: Ie87e0f7d131575bac1cb1099b0a70b230560be9a --- .../launcher3/dragndrop/BaseItemDragListener.java | 214 +++++++++++++++++++++ .../launcher3/dragndrop/PinItemDragListener.java | 179 ++--------------- 2 files changed, 225 insertions(+), 168 deletions(-) create mode 100644 src/com/android/launcher3/dragndrop/BaseItemDragListener.java (limited to 'src/com/android/launcher3/dragndrop') diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java new file mode 100644 index 000000000..d0f2629aa --- /dev/null +++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2017 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.content.ClipDescription; +import android.content.Intent; +import android.graphics.Point; +import android.graphics.Rect; +import android.os.Handler; +import android.os.Looper; +import android.os.Parcel; +import android.os.SystemClock; +import android.util.Log; +import android.view.DragEvent; +import android.view.View; + +import com.android.launcher3.DeleteDropTarget; +import com.android.launcher3.DragSource; +import com.android.launcher3.DropTarget; +import com.android.launcher3.Launcher; +import com.android.launcher3.R; +import com.android.launcher3.folder.Folder; +import com.android.launcher3.widget.PendingItemDragHelper; + +import java.util.UUID; + +/** + * {@link DragSource} for handling drop from a different window. + */ +public abstract class BaseItemDragListener implements + View.OnDragListener, DragSource, DragOptions.PreDragCondition { + + private static final String TAG = "BaseItemDragListener"; + + private static final String MIME_TYPE_PREFIX = "com.android.launcher3.drag_and_drop/"; + public static final String EXTRA_PIN_ITEM_DRAG_LISTENER = "pin_item_drag_listener"; + + // Position of preview relative to the touch location + private final Rect mPreviewRect; + + private final int mPreviewBitmapWidth; + private final int mPreviewViewWidth; + + // Randomly generated id used to verify the drag event. + private final String mId; + + protected Launcher mLauncher; + private DragController mDragController; + private long mDragStartTime; + + public BaseItemDragListener(Rect previewRect, int previewBitmapWidth, int previewViewWidth) { + mPreviewRect = previewRect; + mPreviewBitmapWidth = previewBitmapWidth; + mPreviewViewWidth = previewViewWidth; + mId = UUID.randomUUID().toString(); + } + + protected BaseItemDragListener(Parcel parcel) { + mPreviewRect = Rect.CREATOR.createFromParcel(parcel); + mPreviewBitmapWidth = parcel.readInt(); + mPreviewViewWidth = parcel.readInt(); + mId = parcel.readString(); + } + + protected void writeToParcel(Parcel parcel, int i) { + mPreviewRect.writeToParcel(parcel, i); + parcel.writeInt(mPreviewBitmapWidth); + parcel.writeInt(mPreviewViewWidth); + parcel.writeString(mId); + } + + public String getMimeType() { + return MIME_TYPE_PREFIX + mId; + } + + public void setLauncher(Launcher launcher) { + mLauncher = launcher; + mDragController = launcher.getDragController(); + } + + @Override + public boolean onDrag(View view, DragEvent event) { + if (mLauncher == null || mDragController == null) { + postCleanup(); + return false; + } + if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) { + if (onDragStart(event)) { + return true; + } else { + postCleanup(); + return false; + } + } + return mDragController.onDragEvent(mDragStartTime, event); + } + + protected boolean onDragStart(DragEvent event) { + ClipDescription desc = event.getClipDescription(); + if (desc == null || !desc.hasMimeType(getMimeType())) { + Log.e(TAG, "Someone started a dragAndDrop before us."); + return false; + } + + Point downPos = new Point((int) event.getX(), (int) event.getY()); + DragOptions options = new DragOptions(); + options.systemDndStartPoint = downPos; + options.preDragCondition = this; + + // We use drag event position as the screenPos for the preview image. Since mPreviewRect + // already includes the view position relative to the drag event on the source window, + // and the absolute position (position relative to the screen) of drag event is same + // across windows, using drag position here give a good estimate for relative position + // to source window. + createDragHelper().startDrag(new Rect(mPreviewRect), + mPreviewBitmapWidth, mPreviewViewWidth, downPos, this, options); + mDragStartTime = SystemClock.uptimeMillis(); + return true; + } + + protected abstract PendingItemDragHelper createDragHelper(); + + @Override + public boolean shouldStartDrag(double distanceDragged) { + // Stay in pre-drag mode, if workspace is locked. + return !mLauncher.isWorkspaceLocked(); + } + + @Override + public void onPreDragStart(DropTarget.DragObject dragObject) { + // The predrag starts when the workspace is not yet loaded. In some cases we set + // the dragLayer alpha to 0 to have a nice fade-in animation. But that will prevent the + // dragView from being visible. Instead just skip the fade-in animation here. + mLauncher.getDragLayer().setAlpha(1); + + dragObject.dragView.setColor( + mLauncher.getResources().getColor(R.color.delete_target_hover_tint)); + } + + @Override + public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) { + if (dragStarted) { + dragObject.dragView.setColor(0); + } + } + + @Override + public boolean supportsAppInfoDropTarget() { + return false; + } + + @Override + public boolean supportsDeleteDropTarget() { + return false; + } + + @Override + public float getIntrinsicIconScaleFactor() { + return 1f; + } + + @Override + public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete, + boolean success) { + if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() && + !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) { + // Exit spring loaded mode if we have not successfully dropped or have not handled the + // drop in Workspace + mLauncher.exitSpringLoadedDragModeDelayed(true, + Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null); + } + + if (!success) { + d.deferDragViewCleanupPostAnimation = false; + } + postCleanup(); + } + + private void postCleanup() { + if (mLauncher != null) { + // Remove any drag params from the launcher intent since the drag operation is complete. + Intent newIntent = new Intent(mLauncher.getIntent()); + newIntent.removeExtra(EXTRA_PIN_ITEM_DRAG_LISTENER); + mLauncher.setIntent(newIntent); + } + + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + removeListener(); + } + }); + } + + public void removeListener() { + if (mLauncher != null) { + mLauncher.getDragLayer().setOnDragListener(null); + } + } +} diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java index f9f4e50f7..c8d3890ba 100644 --- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java @@ -18,89 +18,49 @@ package com.android.launcher3.dragndrop; import android.annotation.TargetApi; import android.appwidget.AppWidgetManager; -import android.content.ClipDescription; import android.content.Intent; import android.content.pm.LauncherApps.PinItemRequest; -import android.graphics.Point; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; -import android.os.SystemClock; -import android.util.Log; import android.view.DragEvent; import android.view.View; import android.widget.RemoteViews; -import com.android.launcher3.DeleteDropTarget; import com.android.launcher3.DragSource; -import com.android.launcher3.DropTarget; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.PendingAddItemInfo; -import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.folder.Folder; import com.android.launcher3.userevent.nano.LauncherLogProto; -import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; import com.android.launcher3.widget.PendingItemDragHelper; import com.android.launcher3.widget.WidgetAddFlowHandler; -import java.util.UUID; - /** * {@link DragSource} for handling drop from a different window. This object is initialized * in the source window and is passed on to the Launcher activity as an Intent extra. */ @TargetApi(Build.VERSION_CODES.O) -public class PinItemDragListener - implements Parcelable, View.OnDragListener, DragSource, DragOptions.PreDragCondition { - - private static final String TAG = "PinItemDragListener"; +public class PinItemDragListener extends BaseItemDragListener implements Parcelable { - private static final String MIME_TYPE_PREFIX = "com.android.launcher3.drag_and_drop/"; public static final String EXTRA_PIN_ITEM_DRAG_LISTENER = "pin_item_drag_listener"; private final PinItemRequest mRequest; - // Position of preview relative to the touch location - private final Rect mPreviewRect; - - private final int mPreviewBitmapWidth; - private final int mPreviewViewWidth; - - // Randomly generated id used to verify the drag event. - private final String mId; - - private Launcher mLauncher; - private DragController mDragController; - private long mDragStartTime; - public PinItemDragListener(PinItemRequest request, Rect previewRect, int previewBitmapWidth, int previewViewWidth) { + super(previewRect, previewBitmapWidth, previewViewWidth); mRequest = request; - mPreviewRect = previewRect; - mPreviewBitmapWidth = previewBitmapWidth; - mPreviewViewWidth = previewViewWidth; - mId = UUID.randomUUID().toString(); } private PinItemDragListener(Parcel parcel) { + super(parcel); mRequest = PinItemRequest.CREATOR.createFromParcel(parcel); - mPreviewRect = Rect.CREATOR.createFromParcel(parcel); - mPreviewBitmapWidth = parcel.readInt(); - mPreviewViewWidth = parcel.readInt(); - mId = parcel.readString(); - } - - public String getMimeType() { - return MIME_TYPE_PREFIX + mId; } @Override @@ -110,45 +70,20 @@ public class PinItemDragListener @Override public void writeToParcel(Parcel parcel, int i) { + super.writeToParcel(parcel, i); mRequest.writeToParcel(parcel, i); - mPreviewRect.writeToParcel(parcel, i); - parcel.writeInt(mPreviewBitmapWidth); - parcel.writeInt(mPreviewViewWidth); - parcel.writeString(mId); - } - - public void setLauncher(Launcher launcher) { - mLauncher = launcher; - mDragController = launcher.getDragController(); } @Override - public boolean onDrag(View view, DragEvent event) { - if (mLauncher == null || mDragController == null) { - postCleanup(); - return false; - } - if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) { - if (onDragStart(event)) { - return true; - } else { - postCleanup(); - return false; - } - } - return mDragController.onDragEvent(mDragStartTime, event); - } - - private boolean onDragStart(DragEvent event) { + protected boolean onDragStart(DragEvent event) { if (!mRequest.isValid()) { return false; } - ClipDescription desc = event.getClipDescription(); - if (desc == null || !desc.hasMimeType(getMimeType())) { - Log.e(TAG, "Someone started a dragAndDrop before us."); - return false; - } + return super.onDragStart(event); + } + @Override + protected PendingItemDragHelper createDragHelper() { final PendingAddItemInfo item; if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) { item = new PendingAddShortcutInfo( @@ -170,109 +105,17 @@ public class PinItemDragListener View view = new View(mLauncher); view.setTag(item); - Point downPos = new Point((int) event.getX(), (int) event.getY()); - DragOptions options = new DragOptions(); - options.systemDndStartPoint = downPos; - options.preDragCondition = this; - - // We use drag event position as the screenPos for the preview image. Since mPreviewRect - // already includes the view position relative to the drag event on the source window, - // and the absolute position (position relative to the screen) of drag event is same - // across windows, using drag position here give a good estimate for relative position - // to source window. PendingItemDragHelper dragHelper = new PendingItemDragHelper(view); if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_APPWIDGET) { dragHelper.setPreview(getPreview(mRequest)); } - - dragHelper.startDrag(new Rect(mPreviewRect), - mPreviewBitmapWidth, mPreviewViewWidth, downPos, this, options); - mDragStartTime = SystemClock.uptimeMillis(); - return true; - } - - @Override - public boolean shouldStartDrag(double distanceDragged) { - // Stay in pre-drag mode, if workspace is locked. - return !mLauncher.isWorkspaceLocked(); - } - - @Override - public void onPreDragStart(DropTarget.DragObject dragObject) { - // The predrag starts when the workspace is not yet loaded. In some cases we set - // the dragLayer alpha to 0 to have a nice fade-in animation. But that will prevent the - // dragView from being visible. Instead just skip the fade-in animation here. - mLauncher.getDragLayer().setAlpha(1); - - dragObject.dragView.setColor( - mLauncher.getResources().getColor(R.color.delete_target_hover_tint)); - } - - @Override - public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) { - if (dragStarted) { - dragObject.dragView.setColor(0); - } - } - - @Override - public boolean supportsAppInfoDropTarget() { - return false; - } - - @Override - public boolean supportsDeleteDropTarget() { - return false; - } - - @Override - public float getIntrinsicIconScaleFactor() { - return 1f; - } - - @Override - public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete, - boolean success) { - if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() && - !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) { - // Exit spring loaded mode if we have not successfully dropped or have not handled the - // drop in Workspace - mLauncher.exitSpringLoadedDragModeDelayed(true, - Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null); - } - - if (!success) { - d.deferDragViewCleanupPostAnimation = false; - } - postCleanup(); + return dragHelper; } @Override public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target, LauncherLogProto.Target targetParent) { - targetParent.containerType = ContainerType.PINITEM; - } - - private void postCleanup() { - if (mLauncher != null) { - // Remove any drag params from the launcher intent since the drag operation is complete. - Intent newIntent = new Intent(mLauncher.getIntent()); - newIntent.removeExtra(EXTRA_PIN_ITEM_DRAG_LISTENER); - mLauncher.setIntent(newIntent); - } - - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - removeListener(); - } - }); - } - - public void removeListener() { - if (mLauncher != null) { - mLauncher.getDragLayer().setOnDragListener(null); - } + targetParent.containerType = LauncherLogProto.ContainerType.PINITEM; } public static RemoteViews getPreview(PinItemRequest request) { -- cgit v1.2.3