Code to enable dragging to System UI shelf.
This CL doesn’t let the new code run, it’s under a compile-time flag, and the behavior should be same as before. The change introduces a concept of a DragDriver, which encapsulates behavior of the existing DND (InternalDragDriver) or the framework- driven DND (SystemDragDriver). An instance of DragDriver gets created by DragController for the time while a DND operation is in progress, and it takes care of translating DND events for DragController. Also did some cleanups, like removing meaningless fields etc. Plans for future: keep working in Burnaby, and: * Perhaps, better separate DragDriver from DragController * Detect fling gesture for system DND * Look at accessibility * Polish animations and appearance * Fix dragging from folders * Support cancelling DND Then, it will become possible to enable new dragging (based on Android version). Bug: 22028725 Change-Id: I41b40e9d512d83937f5b101ac8e3e8e7e807c269
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
|
||||
/**
|
||||
* Drop target used when another window (i.e. another process) has accepted a global system drag.
|
||||
* If the accepted item was a shortcut, we delete it from Launcher.
|
||||
*/
|
||||
public class AnotherWindowDropTarget implements DropTarget {
|
||||
final Launcher mLauncher;
|
||||
|
||||
AnotherWindowDropTarget (Context context) { mLauncher = (Launcher) context; }
|
||||
|
||||
@Override
|
||||
public boolean isDropEnabled() { return true; }
|
||||
|
||||
@Override
|
||||
public void onDrop(DragObject dragObject) {
|
||||
dragObject.deferDragViewCleanupPostAnimation = false;
|
||||
LauncherModel.deleteItemFromDatabase(mLauncher, (ShortcutInfo) dragObject.dragInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnter(DragObject dragObject) {}
|
||||
|
||||
@Override
|
||||
public void onDragOver(DragObject dragObject) {}
|
||||
|
||||
@Override
|
||||
public void onDragExit(DragObject dragObject) {}
|
||||
|
||||
@Override
|
||||
public void onFlingToDelete(DragObject dragObject, PointF vec) {}
|
||||
|
||||
@Override
|
||||
public boolean acceptDrop(DragObject dragObject) {
|
||||
return dragObject.dragInfo instanceof ShortcutInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareAccessibilityDrop() {}
|
||||
|
||||
// These methods are implemented in Views
|
||||
@Override
|
||||
public void getHitRectRelativeToDragLayer(Rect outRect) {}
|
||||
|
||||
@Override
|
||||
public void getLocationInDragLayer(int[] loc) {}
|
||||
|
||||
@Override
|
||||
public int getLeft() { return 0; }
|
||||
|
||||
@Override
|
||||
public int getTop() { return 0; }
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.view.DragEvent;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
@@ -73,8 +74,10 @@ public class DragController {
|
||||
private final int[] mCoordinatesTemp = new int[2];
|
||||
private final boolean mIsRtl;
|
||||
|
||||
/** Whether or not we're dragging. */
|
||||
private boolean mDragging;
|
||||
/**
|
||||
* Drag driver for the current drag/drop operation, or null if there is no active DND operation.
|
||||
*/
|
||||
private DragDriver mDragDriver = null;
|
||||
|
||||
/** Whether or not this is an accessible drag operation */
|
||||
private boolean mIsAccessibleDrag;
|
||||
@@ -161,10 +164,6 @@ public class DragController {
|
||||
mIsRtl = Utilities.isRtl(r);
|
||||
}
|
||||
|
||||
public boolean dragging() {
|
||||
return mDragging;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a drag.
|
||||
*
|
||||
@@ -234,8 +233,8 @@ public class DragController {
|
||||
final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
|
||||
final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
|
||||
|
||||
mDragging = true;
|
||||
mIsAccessibleDrag = accessible;
|
||||
mLastDropTarget = null;
|
||||
|
||||
mDragObject = new DropTarget.DragObject();
|
||||
|
||||
@@ -256,6 +255,8 @@ public class DragController {
|
||||
final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX,
|
||||
registrationY, 0, 0, b.getWidth(), b.getHeight(), initialDragViewScale);
|
||||
|
||||
mDragDriver = DragDriver.create(this, dragInfo, dragView);
|
||||
|
||||
if (dragOffset != null) {
|
||||
dragView.setDragVisualizeOffset(new Point(dragOffset));
|
||||
}
|
||||
@@ -318,18 +319,18 @@ public class DragController {
|
||||
* </pre>
|
||||
*/
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
return mDragging;
|
||||
return mDragDriver != null;
|
||||
}
|
||||
|
||||
public boolean isDragging() {
|
||||
return mDragging;
|
||||
return mDragDriver != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop dragging without dropping.
|
||||
*/
|
||||
public void cancelDrag() {
|
||||
if (mDragging) {
|
||||
if (mDragDriver != null) {
|
||||
if (mLastDropTarget != null) {
|
||||
mLastDropTarget.onDragExit(mDragObject);
|
||||
}
|
||||
@@ -363,8 +364,8 @@ public class DragController {
|
||||
}
|
||||
|
||||
private void endDrag() {
|
||||
if (mDragging) {
|
||||
mDragging = false;
|
||||
if (mDragDriver != null) {
|
||||
mDragDriver = null;
|
||||
mIsAccessibleDrag = false;
|
||||
clearScrollRunnable();
|
||||
boolean isDeferred = false;
|
||||
@@ -416,7 +417,7 @@ public class DragController {
|
||||
}
|
||||
|
||||
long getLastGestureUpTime() {
|
||||
if (mDragging) {
|
||||
if (mDragDriver != null) {
|
||||
return System.currentTimeMillis();
|
||||
} else {
|
||||
return mLastTouchUpTime;
|
||||
@@ -427,6 +428,45 @@ public class DragController {
|
||||
mLastTouchUpTime = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this from the drag driver.
|
||||
*/
|
||||
public void onDriverDragMove(float x, float y) {
|
||||
final int[] dragLayerPos = getClampedDragLayerPos(x, y);
|
||||
|
||||
handleMoveEvent(dragLayerPos[0], dragLayerPos[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this from the drag driver.
|
||||
*/
|
||||
public void onDriverDragEnd(float x, float y, DropTarget dropTargetOverride) {
|
||||
final int[] dragLayerPos = getClampedDragLayerPos(x, y);
|
||||
final int dragLayerX = dragLayerPos[0];
|
||||
final int dragLayerY = dragLayerPos[1];
|
||||
|
||||
DropTarget dropTarget;
|
||||
PointF vec = null;
|
||||
|
||||
if (dropTargetOverride != null) {
|
||||
dropTarget = dropTargetOverride;
|
||||
} else {
|
||||
vec = isFlingingToDelete(mDragObject.dragSource);
|
||||
if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
|
||||
vec = null;
|
||||
}
|
||||
if (vec != null) {
|
||||
dropTarget = mFlingToDeleteDropTarget;
|
||||
} else {
|
||||
dropTarget = findDropTarget((int) x, (int) y, mCoordinatesTemp);
|
||||
}
|
||||
}
|
||||
|
||||
drop(dropTarget, x, y, vec);
|
||||
|
||||
endDrag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this from a drag source view.
|
||||
*/
|
||||
@@ -434,8 +474,8 @@ public class DragController {
|
||||
@SuppressWarnings("all") // suppress dead code warning
|
||||
final boolean debug = false;
|
||||
if (debug) {
|
||||
Log.d(Launcher.TAG, "DragController.onInterceptTouchEvent " + ev + " mDragging="
|
||||
+ mDragging);
|
||||
Log.d(Launcher.TAG, "DragController.onInterceptTouchEvent " + ev + " Dragging="
|
||||
+ (mDragDriver != null));
|
||||
}
|
||||
|
||||
if (mIsAccessibleDrag) {
|
||||
@@ -451,35 +491,33 @@ public class DragController {
|
||||
final int dragLayerY = dragLayerPos[1];
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
break;
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// Remember location of down touch
|
||||
mMotionDownX = dragLayerX;
|
||||
mMotionDownY = dragLayerY;
|
||||
mLastDropTarget = null;
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
mLastTouchUpTime = System.currentTimeMillis();
|
||||
if (mDragging) {
|
||||
PointF vec = isFlingingToDelete(mDragObject.dragSource);
|
||||
if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
|
||||
vec = null;
|
||||
}
|
||||
if (vec != null) {
|
||||
dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec);
|
||||
} else {
|
||||
drop(dragLayerX, dragLayerY);
|
||||
}
|
||||
}
|
||||
endDrag();
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
cancelDrag();
|
||||
break;
|
||||
}
|
||||
|
||||
return mDragging;
|
||||
return mDragDriver != null && mDragDriver.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this from a drag source view.
|
||||
*/
|
||||
public boolean onDragEvent(DragEvent event) {
|
||||
return mDragDriver != null && mDragDriver.onDragEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this from a drag view.
|
||||
*/
|
||||
public void onDragViewAnimationEnd() {
|
||||
if (mDragDriver != null ) {
|
||||
mDragDriver.onDragViewAnimationEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -579,7 +617,7 @@ public class DragController {
|
||||
* Call this from a drag source view.
|
||||
*/
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (!mDragging || mIsAccessibleDrag) {
|
||||
if (mDragDriver == null || mIsAccessibleDrag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -592,47 +630,25 @@ public class DragController {
|
||||
final int dragLayerY = dragLayerPos[1];
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// Remember where the motion event started
|
||||
mMotionDownX = dragLayerX;
|
||||
mMotionDownY = dragLayerY;
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// Remember where the motion event started
|
||||
mMotionDownX = dragLayerX;
|
||||
mMotionDownY = dragLayerY;
|
||||
|
||||
if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) {
|
||||
mScrollState = SCROLL_WAITING_IN_ZONE;
|
||||
mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
|
||||
} else {
|
||||
mScrollState = SCROLL_OUTSIDE_ZONE;
|
||||
}
|
||||
handleMoveEvent(dragLayerX, dragLayerY);
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
handleMoveEvent(dragLayerX, dragLayerY);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
// Ensure that we've processed a move event at the current pointer location.
|
||||
handleMoveEvent(dragLayerX, dragLayerY);
|
||||
mHandler.removeCallbacks(mScrollRunnable);
|
||||
|
||||
if (mDragging) {
|
||||
PointF vec = isFlingingToDelete(mDragObject.dragSource);
|
||||
if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
|
||||
vec = null;
|
||||
}
|
||||
if (vec != null) {
|
||||
dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec);
|
||||
if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) {
|
||||
mScrollState = SCROLL_WAITING_IN_ZONE;
|
||||
mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
|
||||
} else {
|
||||
drop(dragLayerX, dragLayerY);
|
||||
mScrollState = SCROLL_OUTSIDE_ZONE;
|
||||
}
|
||||
}
|
||||
endDrag();
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mHandler.removeCallbacks(mScrollRunnable);
|
||||
cancelDrag();
|
||||
break;
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mHandler.removeCallbacks(mScrollRunnable);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
return mDragDriver.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -642,7 +658,6 @@ public class DragController {
|
||||
public void prepareAccessibleDrag(int x, int y) {
|
||||
mMotionDownX = x;
|
||||
mMotionDownY = y;
|
||||
mLastDropTarget = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -660,7 +675,7 @@ public class DragController {
|
||||
|
||||
dropTarget.prepareAccessibilityDrop();
|
||||
// Perform the drop
|
||||
drop(location[0], location[1]);
|
||||
drop(dropTarget, location[0], location[1], null);
|
||||
endDrag();
|
||||
}
|
||||
|
||||
@@ -690,49 +705,41 @@ public class DragController {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void dropOnFlingToDeleteTarget(float x, float y, PointF vel) {
|
||||
void drop(DropTarget dropTarget, float x, float y, PointF flingVel) {
|
||||
final int[] coordinates = mCoordinatesTemp;
|
||||
|
||||
mDragObject.x = coordinates[0];
|
||||
mDragObject.y = coordinates[1];
|
||||
|
||||
// Clean up dragging on the target if it's not the current fling delete target otherwise,
|
||||
// start dragging to it.
|
||||
if (mLastDropTarget != null && mFlingToDeleteDropTarget != mLastDropTarget) {
|
||||
mLastDropTarget.onDragExit(mDragObject);
|
||||
// Move dragging to the final target.
|
||||
if (dropTarget != mLastDropTarget) {
|
||||
if (mLastDropTarget != null) {
|
||||
mLastDropTarget.onDragExit(mDragObject);
|
||||
}
|
||||
mLastDropTarget = dropTarget;
|
||||
if (dropTarget != null) {
|
||||
dropTarget.onDragEnter(mDragObject);
|
||||
}
|
||||
}
|
||||
|
||||
// Drop onto the fling-to-delete target
|
||||
boolean accepted = false;
|
||||
mFlingToDeleteDropTarget.onDragEnter(mDragObject);
|
||||
// We must set dragComplete to true _only_ after we "enter" the fling-to-delete target for
|
||||
// "drop"
|
||||
mDragObject.dragComplete = true;
|
||||
mFlingToDeleteDropTarget.onDragExit(mDragObject);
|
||||
if (mFlingToDeleteDropTarget.acceptDrop(mDragObject)) {
|
||||
mFlingToDeleteDropTarget.onFlingToDelete(mDragObject, vel);
|
||||
accepted = true;
|
||||
}
|
||||
mDragObject.dragSource.onDropCompleted((View) mFlingToDeleteDropTarget, mDragObject, true,
|
||||
accepted);
|
||||
}
|
||||
|
||||
private void drop(float x, float y) {
|
||||
final int[] coordinates = mCoordinatesTemp;
|
||||
final DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
|
||||
|
||||
mDragObject.x = coordinates[0];
|
||||
mDragObject.y = coordinates[1];
|
||||
// Drop onto the target.
|
||||
boolean accepted = false;
|
||||
if (dropTarget != null) {
|
||||
mDragObject.dragComplete = true;
|
||||
dropTarget.onDragExit(mDragObject);
|
||||
if (dropTarget.acceptDrop(mDragObject)) {
|
||||
dropTarget.onDrop(mDragObject);
|
||||
if (flingVel != null) {
|
||||
dropTarget.onFlingToDelete(mDragObject, flingVel);
|
||||
} else {
|
||||
dropTarget.onDrop(mDragObject);
|
||||
}
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
mDragObject.dragSource.onDropCompleted((View) dropTarget, mDragObject, false, accepted);
|
||||
final View dropTargetAsView = dropTarget instanceof View ? (View) dropTarget : null;
|
||||
mDragObject.dragSource.onDropCompleted(
|
||||
dropTargetAsView, mDragObject, flingVel != null, accepted);
|
||||
}
|
||||
|
||||
private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Point;
|
||||
import android.view.DragEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Base class for driving a drag/drop operation.
|
||||
*/
|
||||
public abstract class DragDriver {
|
||||
protected final DragController mDragController;
|
||||
|
||||
public DragDriver(DragController dragController) {
|
||||
mDragController = dragController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles ending of the DragView animation.
|
||||
*/
|
||||
public abstract void onDragViewAnimationEnd();
|
||||
|
||||
public abstract boolean onTouchEvent(MotionEvent ev);
|
||||
|
||||
public abstract boolean onDragEvent (DragEvent event);
|
||||
|
||||
public abstract boolean onInterceptTouchEvent(MotionEvent ev);
|
||||
|
||||
public static DragDriver create(
|
||||
DragController dragController, ItemInfo dragInfo, DragView dragView) {
|
||||
// TODO: Replace the hardcoded constant with looking at the API version.
|
||||
final boolean useSystemDrag = false;
|
||||
|
||||
if (useSystemDrag) {
|
||||
return new SystemDragDriver(dragController, dragInfo.getIntent(), dragView);
|
||||
} else {
|
||||
return new InternalDragDriver(dragController);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for driving a system (i.e. framework) drag/drop operation.
|
||||
*/
|
||||
class SystemDragDriver extends DragDriver {
|
||||
/** Intent associated with the drag operation, or null is there no associated intent. */
|
||||
private final Intent mDragIntent;
|
||||
|
||||
private final DragView mDragView;
|
||||
boolean mDragging = false;
|
||||
boolean mReceivedDropEvent = false;
|
||||
float mLastX = 0;
|
||||
float mLastY = 0;
|
||||
|
||||
public SystemDragDriver(DragController dragController, Intent dragIntent, DragView dragView) {
|
||||
super(dragController);
|
||||
mDragIntent = dragIntent;
|
||||
mDragView = dragView;
|
||||
}
|
||||
|
||||
private static class ShadowBuilder extends View.DragShadowBuilder {
|
||||
final DragView mDragView;
|
||||
|
||||
public ShadowBuilder(DragView dragView) {
|
||||
mDragView = dragView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideShadowMetrics (Point size, Point touch) {
|
||||
mDragView.provideDragShadowMetrics(size, touch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawShadow(Canvas canvas) {
|
||||
mDragView.drawDragShadow(canvas);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onDragViewAnimationEnd() {
|
||||
// Clip data for the drag operation. If there is an intent, create an intent-based ClipData,
|
||||
// which will be passed to a global DND.
|
||||
// If there is no intent, craft a fake ClipData and start a local DND operation; this
|
||||
// ClipData will be ignored.
|
||||
final ClipData dragData = mDragIntent != null ?
|
||||
ClipData.newIntent("", mDragIntent) :
|
||||
ClipData.newPlainText("", "");
|
||||
|
||||
View.DragShadowBuilder shadowBuilder = new ShadowBuilder(mDragView);
|
||||
// TODO: DND flags are in flux, once settled, use the appropriate constant.
|
||||
final int flags = mDragIntent != null ? 1 : 0;
|
||||
|
||||
mDragging = true;
|
||||
|
||||
if (!mDragView.startDrag(dragData, shadowBuilder, null, flags)) {
|
||||
mDragging = false;
|
||||
mDragController.cancelDrag();
|
||||
return;
|
||||
}
|
||||
|
||||
// Starting from this point, the driver takes over showing the drag shadow, so hiding the
|
||||
// drag view.
|
||||
mDragView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDragEvent (DragEvent event) {
|
||||
if (!mDragging) {
|
||||
// We are interested only in drag events started by this driver.
|
||||
return false;
|
||||
}
|
||||
|
||||
final int action = event.getAction();
|
||||
|
||||
switch (action) {
|
||||
case DragEvent.ACTION_DRAG_STARTED:
|
||||
return true;
|
||||
|
||||
case DragEvent.ACTION_DRAG_ENTERED:
|
||||
return true;
|
||||
|
||||
case DragEvent.ACTION_DRAG_LOCATION:
|
||||
mLastX = event.getX();
|
||||
mLastY = event.getY();
|
||||
mDragController.onDriverDragMove(event.getX(), event.getY());
|
||||
return true;
|
||||
|
||||
case DragEvent.ACTION_DROP:
|
||||
mReceivedDropEvent = true;
|
||||
return true;
|
||||
|
||||
case DragEvent.ACTION_DRAG_EXITED:
|
||||
return true;
|
||||
|
||||
case DragEvent.ACTION_DRAG_ENDED:
|
||||
final boolean dragAccepted = event.getResult();
|
||||
final boolean acceptedByAnotherWindow = dragAccepted && !mReceivedDropEvent;
|
||||
|
||||
// When the system drag ends, its drag shadow disappears. Resume showing the drag
|
||||
// view for the possible final animation.
|
||||
mDragView.setVisibility(View.VISIBLE);
|
||||
|
||||
final DropTarget dropTargetOverride = acceptedByAnotherWindow ?
|
||||
new AnotherWindowDropTarget(mDragView.getContext()) : null;
|
||||
|
||||
mDragController.onDriverDragEnd(mLastX, mLastY, dropTargetOverride);
|
||||
mDragging = false;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for driving an internal (i.e. not using framework) drag/drop operation.
|
||||
*/
|
||||
class InternalDragDriver extends DragDriver {
|
||||
public InternalDragDriver(DragController dragController) {
|
||||
super(dragController);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragViewAnimationEnd() {}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
final int action = ev.getAction();
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mDragController.onDriverDragMove(ev.getX(), ev.getY());
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
mDragController.onDriverDragMove(ev.getX(), ev.getY());
|
||||
mDragController.onDriverDragEnd(ev.getX(), ev.getY(), null);
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mDragController.cancelDrag();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
final int action = ev.getAction();
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
mDragController.onDriverDragEnd(ev.getX(), ev.getY(), null);
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mDragController.cancelDrag();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDragEvent (DragEvent event) { return false; }
|
||||
};
|
||||
@@ -28,6 +28,7 @@ import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.DragEvent;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -375,6 +376,11 @@ public class DragLayer extends InsettableFrameLayout {
|
||||
return mDragController.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDragEvent (DragEvent event) {
|
||||
return mDragController.onDragEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the rect of the descendant in this DragLayer's coordinates
|
||||
*
|
||||
@@ -764,7 +770,7 @@ public class DragLayer extends InsettableFrameLayout {
|
||||
// Show the drop view if it was previously hidden
|
||||
mDropView = view;
|
||||
mDropView.cancelAnimation();
|
||||
mDropView.resetLayoutParams();
|
||||
mDropView.requestLayout();
|
||||
|
||||
// Set the anchor view if the page is scrolling
|
||||
if (anchorView != null) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.FloatArrayEvaluator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
@@ -45,18 +47,17 @@ public class DragView extends View {
|
||||
private Bitmap mBitmap;
|
||||
private Bitmap mCrossFadeBitmap;
|
||||
@Thunk Paint mPaint;
|
||||
private int mRegistrationX;
|
||||
private int mRegistrationY;
|
||||
private final int mRegistrationX;
|
||||
private final int mRegistrationY;
|
||||
|
||||
private Point mDragVisualizeOffset = null;
|
||||
private Rect mDragRegion = null;
|
||||
private DragLayer mDragLayer = null;
|
||||
private final DragLayer mDragLayer;
|
||||
private final DragController mDragController;
|
||||
private boolean mHasDrawn = false;
|
||||
@Thunk float mCrossFadeProgress = 0f;
|
||||
|
||||
ValueAnimator mAnim;
|
||||
@Thunk float mOffsetX = 0.0f;
|
||||
@Thunk float mOffsetY = 0.0f;
|
||||
private float mInitialScale = 1f;
|
||||
// The intrinsic icon scale factor is the scale factor for a drag icon over the workspace
|
||||
// size. This is ignored for non-icons.
|
||||
@@ -81,6 +82,7 @@ public class DragView extends View {
|
||||
int left, int top, int width, int height, final float initialScale) {
|
||||
super(launcher);
|
||||
mDragLayer = launcher.getDragLayer();
|
||||
mDragController = launcher.getDragController();
|
||||
mInitialScale = initialScale;
|
||||
|
||||
final Resources res = getResources();
|
||||
@@ -99,11 +101,6 @@ public class DragView extends View {
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
final float value = (Float) animation.getAnimatedValue();
|
||||
|
||||
final int deltaX = (int) (-mOffsetX);
|
||||
final int deltaY = (int) (-mOffsetY);
|
||||
|
||||
mOffsetX += deltaX;
|
||||
mOffsetY += deltaY;
|
||||
setScaleX(initialScale + (value * (scale - initialScale)));
|
||||
setScaleY(initialScale + (value * (scale - initialScale)));
|
||||
if (sDragAlpha != 1f) {
|
||||
@@ -112,13 +109,17 @@ public class DragView extends View {
|
||||
|
||||
if (getParent() == null) {
|
||||
animation.cancel();
|
||||
} else {
|
||||
setTranslationX(getTranslationX() + deltaX);
|
||||
setTranslationY(getTranslationY() + deltaY);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mDragController.onDragViewAnimationEnd();
|
||||
}
|
||||
});
|
||||
|
||||
mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height);
|
||||
setDragRegion(new Rect(0, 0, width, height));
|
||||
|
||||
@@ -145,10 +146,6 @@ public class DragView extends View {
|
||||
return mIntrinsicIconScale;
|
||||
}
|
||||
|
||||
public float getOffsetY() {
|
||||
return mOffsetY;
|
||||
}
|
||||
|
||||
public int getDragRegionLeft() {
|
||||
return mDragRegion.left;
|
||||
}
|
||||
@@ -181,10 +178,6 @@ public class DragView extends View {
|
||||
return mDragRegion;
|
||||
}
|
||||
|
||||
public float getInitialScale() {
|
||||
return mInitialScale;
|
||||
}
|
||||
|
||||
public void updateInitialScaleToCurrentScale() {
|
||||
mInitialScale = getScaleX();
|
||||
}
|
||||
@@ -194,6 +187,23 @@ public class DragView extends View {
|
||||
setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
|
||||
}
|
||||
|
||||
// Draws drag shadow for system DND.
|
||||
public void drawDragShadow(Canvas canvas) {
|
||||
final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
|
||||
canvas.scale(getScaleX(), getScaleY());
|
||||
onDraw(canvas);
|
||||
canvas.restoreToCount(saveCount);
|
||||
}
|
||||
|
||||
// Provides drag shadow metrics for system DND.
|
||||
public void provideDragShadowMetrics(Point size, Point touch) {
|
||||
size.set((int)(mBitmap.getWidth() * getScaleX()), (int)(mBitmap.getHeight() * getScaleY()));
|
||||
|
||||
final int xGrowth = (int)(mBitmap.getWidth() * (getScaleX() - mInitialScale));
|
||||
final int yGrowth = (int)(mBitmap.getHeight() * (getScaleY() - mInitialScale));
|
||||
touch.set(mRegistrationX + xGrowth / 2, mRegistrationY + yGrowth / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
@SuppressWarnings("all") // suppress dead code warning
|
||||
@@ -214,12 +224,12 @@ public class DragView extends View {
|
||||
canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
|
||||
if (crossFade) {
|
||||
mPaint.setAlpha((int) (255 * mCrossFadeProgress));
|
||||
canvas.save();
|
||||
final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
|
||||
float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
|
||||
float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
|
||||
canvas.scale(sX, sY);
|
||||
canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
|
||||
canvas.restore();
|
||||
canvas.restoreToCount(saveCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,11 +343,6 @@ public class DragView extends View {
|
||||
}
|
||||
}
|
||||
|
||||
public void resetLayoutParams() {
|
||||
mOffsetX = mOffsetY = 0;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the window containing this view.
|
||||
*
|
||||
@@ -345,8 +350,8 @@ public class DragView extends View {
|
||||
* @param touchY the y coordinate the user touched in DragLayer coordinates
|
||||
*/
|
||||
void move(int touchX, int touchY) {
|
||||
setTranslationX(touchX - mRegistrationX + (int) mOffsetX);
|
||||
setTranslationY(touchY - mRegistrationY + (int) mOffsetY);
|
||||
setTranslationX(touchX - mRegistrationX);
|
||||
setTranslationY(touchY - mRegistrationY);
|
||||
}
|
||||
|
||||
void remove() {
|
||||
|
||||
@@ -134,7 +134,7 @@ public class ItemInfo {
|
||||
}
|
||||
|
||||
public Intent getIntent() {
|
||||
throw new RuntimeException("Unexpected Intent");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user