From 00acb123c5100f06b8e89e8ec8978ebafc6f6d26 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Tue, 4 Aug 2009 16:04:30 -0400 Subject: Move the drag thing into its own window that goes around on top of everything else. --- src/com/android/launcher2/AllAppsGridView.java | 26 +- src/com/android/launcher2/DeleteZone.java | 37 +- src/com/android/launcher2/DragController.java | 467 +++++++++++++++++++- src/com/android/launcher2/DragLayer.java | 575 +------------------------ src/com/android/launcher2/DragSource.java | 2 +- src/com/android/launcher2/DragView.java | 186 ++++++++ src/com/android/launcher2/DropTarget.java | 33 +- src/com/android/launcher2/Folder.java | 8 +- src/com/android/launcher2/FolderIcon.java | 14 +- src/com/android/launcher2/Launcher.java | 45 +- src/com/android/launcher2/LiveFolderIcon.java | 15 +- src/com/android/launcher2/UserFolder.java | 17 +- src/com/android/launcher2/Workspace.java | 45 +- 13 files changed, 807 insertions(+), 663 deletions(-) create mode 100644 src/com/android/launcher2/DragView.java (limited to 'src/com') diff --git a/src/com/android/launcher2/AllAppsGridView.java b/src/com/android/launcher2/AllAppsGridView.java index cca9ed2ef..711e213dc 100644 --- a/src/com/android/launcher2/AllAppsGridView.java +++ b/src/com/android/launcher2/AllAppsGridView.java @@ -30,8 +30,9 @@ import android.graphics.Canvas; public class AllAppsGridView extends GridView implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, DragSource { - private DragController mDragger; + private DragController mDragController; private Launcher mLauncher; + private boolean mDraw = true; public AllAppsGridView(Context context) { super(context); @@ -64,20 +65,33 @@ public class AllAppsGridView extends GridView implements AdapterView.OnItemClick ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position); app = new ApplicationInfo(app); - mDragger.startDrag(view, this, app, DragController.DRAG_ACTION_COPY); - mLauncher.closeAllApplications(); - + mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY); + mLauncher.showWorkspace(); + mDraw = false; + invalidate(); return true; } - public void setDragger(DragController dragger) { - mDragger = dragger; + @Override + protected void dispatchDraw(Canvas canvas) { + if (mDraw) { + super.dispatchDraw(canvas); + } + } + + public void setDragController(DragController dragController) { + mDragController = dragController; } public void onDropCompleted(View target, boolean success) { + mLauncher.closeAllAppsDialog(false); } void setLauncher(Launcher launcher) { mLauncher = launcher; } + + void onPrepareDialog() { + mDraw = true; + } } diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java index f7266256e..8a2545fd5 100644 --- a/src/com/android/launcher2/DeleteZone.java +++ b/src/com/android/launcher2/DeleteZone.java @@ -19,6 +19,9 @@ package com.android.launcher2; import android.widget.ImageView; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; @@ -46,15 +49,12 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. private Animation mHandleOutAnimation; private int mOrientation; - private DragLayer mDragLayer; + private DragController mDragController; private final RectF mRegion = new RectF(); private TransitionDrawable mTransition; private View mHandle; - - public DeleteZone(Context context) { - super(context); - } + private final Paint mTrashPaint = new Paint(); public DeleteZone(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -63,6 +63,9 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. public DeleteZone(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + final int srcColor = context.getResources().getColor(R.color.delete_color_filter); + mTrashPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP)); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DeleteZone, defStyle, 0); mOrientation = a.getInt(R.styleable.DeleteZone_direction, ORIENTATION_HORIZONTAL); a.recycle(); @@ -75,15 +78,17 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. } public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { return true; } - public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle) { + public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo, Rect recycle) { return null; } - public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { final ItemInfo item = (ItemInfo) dragInfo; if (item.container == -1) return; @@ -117,17 +122,19 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. } public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { mTransition.reverseTransition(TRANSITION_DURATION); + dragView.setPaint(mTrashPaint); } public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { } public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { mTransition.reverseTransition(TRANSITION_DURATION); + dragView.setPaint(null); } public void onDragStart(View v, DragSource source, Object info, int dragAction) { @@ -139,7 +146,7 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. getLocationOnScreen(location); mRegion.set(location[0], location[1], location[0] + mRight - mLeft, location[1] + mBottom - mTop); - mDragLayer.setDeleteRegion(mRegion); + mDragController.setDeleteRegion(mRegion); mTransition.resetTransition(); startAnimation(mInAnimation); mHandle.startAnimation(mHandleOutAnimation); @@ -150,7 +157,7 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. public void onDragEnd() { if (mTrashMode) { mTrashMode = false; - mDragLayer.setDeleteRegion(null); + mDragController.setDeleteRegion(null); startAnimation(mOutAnimation); mHandle.startAnimation(mHandleInAnimation); setVisibility(GONE); @@ -221,8 +228,8 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. mLauncher = launcher; } - void setDragController(DragLayer dragLayer) { - mDragLayer = dragLayer; + void setDragController(DragController dragController) { + mDragController = dragController; } void setHandle(View view) { diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java index f8c80775d..da2df5c97 100644 --- a/src/com/android/launcher2/DragController.java +++ b/src/com/android/launcher2/DragController.java @@ -16,14 +16,108 @@ package com.android.launcher2; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.RectF; +import android.os.IBinder; +import android.os.Handler; +import android.os.Vibrator; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.util.Log; import android.view.View; +import android.view.ViewGroup; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.inputmethod.InputMethodManager; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import java.util.ArrayList; /** - * Interface for initiating a drag within a view or across multiple views. - * + * Class for initiating a drag within a view or across multiple views. */ -public interface DragController { - +public class DragController { + /** Indicates the drag is a move. */ + public static int DRAG_ACTION_MOVE = 0; + + /** Indicates the drag is a copy. */ + public static int DRAG_ACTION_COPY = 1; + + private static final int SCROLL_DELAY = 600; + private static final int SCROLL_ZONE = 20; + private static final int VIBRATE_DURATION = 35; + + private static final boolean PROFILE_DRAWING_DURING_DRAG = false; + + private static final int SCROLL_OUTSIDE_ZONE = 0; + private static final int SCROLL_WAITING_IN_ZONE = 1; + + private static final int SCROLL_LEFT = 0; + private static final int SCROLL_RIGHT = 1; + + private Context mContext; + private Handler mHandler; + private final Vibrator mVibrator = new Vibrator(); + + // temporaries to avoid gc thrash + private Rect mRectTemp = new Rect(); + private final int[] mCoordinatesTemp = new int[2]; + + /** Whether or not we're dragging. */ + private boolean mDragging; + + /** X coordinate of the down event. */ + private float mMotionDownX; + + /** Y coordinate of the down event. */ + private float mMotionDownY; + + /** Original view that is being dragged. */ + private View mOriginator; + + /** The contents of mOriginator with no scaling. */ + private Bitmap mDragBitmap; + + /** X offset from the upper-left corner of the cell to where we touched. */ + private float mTouchOffsetX; + + /** Y offset from the upper-left corner of the cell to where we touched. */ + private float mTouchOffsetY; + + /** Where the drag originated */ + private DragSource mDragSource; + + /** The data associated with the object being dragged */ + private Object mDragInfo; + + /** The view that moves around while you drag. */ + private DragView mDragView; + + /** Who can receive drop events */ + private ArrayList mDropTargets = new ArrayList(); + + private DragListener mListener; + + /** The window token used as the parent for the DragView. */ + private IBinder mWindowToken; + + /** The view that will be scrolled when dragging to the left and right edges of the screen. */ + private View mScrollView; + + private DragScroller mDragScroller; + private int mScrollState = SCROLL_OUTSIDE_ZONE; + private ScrollRunnable mScrollRunnable = new ScrollRunnable(); + + private RectF mDeleteRegion; + private DropTarget mLastDropTarget; + + private InputMethodManager mInputMethodManager; + /** * Interface to receive notifications when a drag starts or stops */ @@ -47,14 +141,15 @@ public interface DragController { } /** - * Indicates the drag is a move. - */ - public static int DRAG_ACTION_MOVE = 0; - - /** - * Indicates the drag is a copy. + * Used to create a new DragLayer from XML. + * + * @param context The application's context. + * @param attrs The attribtues set containing the Workspace's customization values. */ - public static int DRAG_ACTION_COPY = 1; + public DragController(Context context) { + mContext = context; + mHandler = new Handler(); + } /** * Starts a drag @@ -65,15 +160,355 @@ public interface DragController { * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or * {@link #DRAG_ACTION_COPY} */ - void startDrag(View v, DragSource source, Object info, int dragAction); - + public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) { + if (PROFILE_DRAWING_DURING_DRAG) { + android.os.Debug.startMethodTracing("Launcher"); + } + + // Hide soft keyboard, if visible + if (mInputMethodManager == null) { + mInputMethodManager = (InputMethodManager) + mContext.getSystemService(Context.INPUT_METHOD_SERVICE); + } + mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0); + + if (mListener != null) { + mListener.onDragStart(v, source, dragInfo, dragAction); + } + + int[] loc = mCoordinatesTemp; + v.getLocationOnScreen(loc); + int screenX = loc[0]; + int screenY = loc[1]; + + int registrationX = ((int)mMotionDownX) - screenX; + int registrationY = ((int)mMotionDownY) - screenY; + + mTouchOffsetX = mMotionDownX - screenX; + mTouchOffsetY = mMotionDownY - screenY; + + mDragging = true; + mOriginator = v; + mDragSource = source; + mDragInfo = dragInfo; + + mVibrator.vibrate(VIBRATE_DURATION); + + mDragBitmap = getViewBitmap(v); + DragView dragView = mDragView = new DragView(mContext, mDragBitmap, + registrationX, registrationY); + dragView.show(mWindowToken, (int)mMotionDownX, (int)mMotionDownY); + + if (dragAction == DRAG_ACTION_MOVE) { + v.setVisibility(View.GONE); + } + } + + /** + * Draw the view into a bitmap. + */ + private Bitmap getViewBitmap(View v) { + v.clearFocus(); + v.setPressed(false); + + boolean willNotCache = v.willNotCacheDrawing(); + v.setWillNotCacheDrawing(false); + + // Reset the drawing cache background color to fully transparent + // for the duration of this operation + int color = v.getDrawingCacheBackgroundColor(); + v.setDrawingCacheBackgroundColor(0); + + if (color != 0) { + v.destroyDrawingCache(); + } + v.buildDrawingCache(); + Bitmap cacheBitmap = v.getDrawingCache(); + + Bitmap bitmap = Bitmap.createBitmap(cacheBitmap); + + // Restore the view + v.destroyDrawingCache(); + v.setWillNotCacheDrawing(willNotCache); + v.setDrawingCacheBackgroundColor(color); + + return bitmap; + } + + /** + * Call this from a drag source view like this: + * + *
+     *  @Override
+     *  public boolean dispatchKeyEvent(KeyEvent event) {
+     *      return mDragController.dispatchKeyEvent(this, event)
+     *              || super.dispatchKeyEvent(event);
+     * 
+ */ + public boolean dispatchKeyEvent(KeyEvent event) { + return mDragging; + } + + private void endDrag() { + if (mDragging) { + mDragging = false; + if (mOriginator != null) { + mOriginator.setVisibility(View.VISIBLE); + } + if (mListener != null) { + mListener.onDragEnd(); + } + if (mDragView != null) { + mDragView.remove(); + mDragView = null; + } + if (mDragBitmap != null) { + mDragBitmap.recycle(); + mDragBitmap = null; + } + } + } + + /** + * Call this from a drag source view. + */ + public boolean onInterceptTouchEvent(MotionEvent ev) { + final int action = ev.getAction(); + + final float screenX = ev.getRawX(); + final float screenY = ev.getRawY(); + + switch (action) { + case MotionEvent.ACTION_MOVE: + break; + + case MotionEvent.ACTION_DOWN: + // Remember location of down touch + mMotionDownX = screenX; + mMotionDownY = screenY; + mLastDropTarget = null; + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + if (mDragging) { + drop(screenX, screenY); + } + endDrag(); + break; + } + + return mDragging; + } + + /** + * Call this from a drag source view. + */ + public boolean onTouchEvent(MotionEvent ev) { + View scrollView = mScrollView; + + if (!mDragging) { + return false; + } + + final int action = ev.getAction(); + final float x = ev.getRawX(); + final float y = ev.getRawY(); + + switch (action) { + case MotionEvent.ACTION_DOWN: + + // Remember where the motion event started + mMotionDownX = x; + mMotionDownY = y; + + if ((x < SCROLL_ZONE) || (x > scrollView.getWidth() - SCROLL_ZONE)) { + mScrollState = SCROLL_WAITING_IN_ZONE; + mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY); + } else { + mScrollState = SCROLL_OUTSIDE_ZONE; + } + + break; + case MotionEvent.ACTION_MOVE: + // Update the drag view. + mDragView.move((int)ev.getRawX(), (int)ev.getRawY()); + + // Drop on someone? + final int[] coordinates = mCoordinatesTemp; + DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates); + if (dropTarget != null) { + if (mLastDropTarget == dropTarget) { + dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1], + (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo); + } else { + if (mLastDropTarget != null) { + mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1], + (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo); + } + dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1], + (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo); + } + } else { + if (mLastDropTarget != null) { + mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1], + (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo); + } + } + mLastDropTarget = dropTarget; + + // Scroll, maybe, but not if we're in the delete region. + boolean inDeleteRegion = false; + if (mDeleteRegion != null) { + inDeleteRegion = mDeleteRegion.contains(ev.getRawX(), ev.getRawY()); + } + if (!inDeleteRegion && x < SCROLL_ZONE) { + if (mScrollState == SCROLL_OUTSIDE_ZONE) { + mScrollState = SCROLL_WAITING_IN_ZONE; + mScrollRunnable.setDirection(SCROLL_LEFT); + mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY); + } + } else if (!inDeleteRegion && x > scrollView.getWidth() - SCROLL_ZONE) { + if (mScrollState == SCROLL_OUTSIDE_ZONE) { + mScrollState = SCROLL_WAITING_IN_ZONE; + mScrollRunnable.setDirection(SCROLL_RIGHT); + mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY); + } + } else { + if (mScrollState == SCROLL_WAITING_IN_ZONE) { + mScrollState = SCROLL_OUTSIDE_ZONE; + mScrollRunnable.setDirection(SCROLL_RIGHT); + mHandler.removeCallbacks(mScrollRunnable); + } + } + + break; + case MotionEvent.ACTION_UP: + mHandler.removeCallbacks(mScrollRunnable); + if (mDragging) { + drop(x, y); + } + endDrag(); + + break; + case MotionEvent.ACTION_CANCEL: + endDrag(); + } + + return true; + } + + private boolean drop(float x, float y) { + final int[] coordinates = mCoordinatesTemp; + DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates); + + if (dropTarget != null) { + dropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1], + (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo); + if (dropTarget.acceptDrop(mDragSource, coordinates[0], coordinates[1], + (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo)) { + dropTarget.onDrop(mDragSource, coordinates[0], coordinates[1], + (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo); + mDragSource.onDropCompleted((View) dropTarget, true); + return true; + } else { + mDragSource.onDropCompleted((View) dropTarget, false); + return true; + } + } + return false; + } + + private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) { + final Rect r = mRectTemp; + + final ArrayList dropTargets = mDropTargets; + final int count = dropTargets.size(); + for (int i=count-1; i>=0; i--) { + final DropTarget target = dropTargets.get(i); + target.getHitRect(r); + target.getLocationOnScreen(dropCoordinates); + r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop()); + if (r.contains(x, y)) { + dropCoordinates[0] = x - dropCoordinates[0]; + dropCoordinates[1] = y - dropCoordinates[1]; + return target; + } + } + return null; + } + + public void setDragScoller(DragScroller scroller) { + mDragScroller = scroller; + } + + public void setWindowToken(IBinder token) { + mWindowToken = token; + } + /** * Sets the drag listner which will be notified when a drag starts or ends. */ - void setDragListener(DragListener l); - + public void setDragListener(DragListener l) { + mListener = l; + } + /** * Remove a previously installed drag listener. */ - void removeDragListener(DragListener l); + public void removeDragListener(DragListener l) { + mListener = null; + } + + /** + * Add a DropTarget to the list of potential places to receive drop events. + */ + public void addDropTarget(DropTarget target) { + mDropTargets.add(target); + } + + /** + * Don't send drop events to target any more. + */ + public void removeDropTarget(DropTarget target) { + mDropTargets.remove(target); + } + + /** + * Set which view scrolls for touch events near the edge of the screen. + */ + public void setScrollView(View v) { + mScrollView = v; + } + + /** + * Specifies the delete region. We won't scroll on touch events over the delete region. + * + * @param region The rectangle in screen coordinates of the delete region. + */ + void setDeleteRegion(RectF region) { + mDeleteRegion = region; + } + + private class ScrollRunnable implements Runnable { + private int mDirection; + + ScrollRunnable() { + } + + public void run() { + if (mDragScroller != null) { + if (mDirection == SCROLL_LEFT) { + mDragScroller.scrollLeft(); + } else { + mDragScroller.scrollRight(); + } + mScrollState = SCROLL_OUTSIDE_ZONE; + } + } + + void setDirection(int direction) { + mDirection = direction; + } + } } diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java index fee86326c..28397119a 100644 --- a/src/com/android/launcher2/DragLayer.java +++ b/src/com/android/launcher2/DragLayer.java @@ -39,114 +39,9 @@ import android.widget.FrameLayout; /** * A ViewGroup that coordinated dragging across its dscendants */ -public class DragLayer extends FrameLayout implements DragController { - private static final int SCROLL_DELAY = 600; - private static final int SCROLL_ZONE = 20; - private static final int VIBRATE_DURATION = 35; - private static final int ANIMATION_SCALE_UP_DURATION = 110; +public class DragLayer extends FrameLayout { - private static final boolean PROFILE_DRAWING_DURING_DRAG = false; - - // Number of pixels to add to the dragged item for scaling - private static final float DRAG_SCALE = 24.0f; - - private boolean mDragging = false; - private boolean mShouldDrop; - private float mLastMotionX; - private float mLastMotionY; - - /** - * The bitmap that is currently being dragged - */ - private Bitmap mDragBitmap = null; - private View mOriginator; - - private int mBitmapOffsetX; - private int mBitmapOffsetY; - - /** - * X offset from where we touched on the cell to its upper-left corner - */ - private float mTouchOffsetX; - - /** - * Y offset from where we touched on the cell to its upper-left corner - */ - private float mTouchOffsetY; - - /** - * Utility rectangle - */ - private Rect mDragRect = new Rect(); - - /** - * Where the drag originated - */ - private DragSource mDragSource; - - /** - * The data associated with the object being dragged - */ - private Object mDragInfo; - - private final Rect mRect = new Rect(); - private final int[] mDropCoordinates = new int[2]; - - private final Vibrator mVibrator = new Vibrator(); - - private DragListener mListener; - - private DragScroller mDragScroller; - - private static final int SCROLL_OUTSIDE_ZONE = 0; - private static final int SCROLL_WAITING_IN_ZONE = 1; - - private static final int SCROLL_LEFT = 0; - private static final int SCROLL_RIGHT = 1; - - private int mScrollState = SCROLL_OUTSIDE_ZONE; - - private ScrollRunnable mScrollRunnable = new ScrollRunnable(); - private View mIgnoredDropTarget; - - private RectF mDragRegion; - private boolean mEnteredRegion; - private DropTarget mLastDropTarget; - - private final Paint mTrashPaint = new Paint(); - private final Paint mEstimatedPaint = new Paint(); - private Paint mDragPaint; - - /** - * If true, draw a "snag" showing where the object currently being dragged - * would end up if dropped from current location. - */ - private static final boolean DRAW_TARGET_SNAG = false; - - private Rect mEstimatedRect = new Rect(); - private float[] mDragCenter = new float[2]; - private float[] mEstimatedCenter = new float[2]; - private boolean mDrawEstimated = false; - - private int mTriggerWidth = -1; - private int mTriggerHeight = -1; - - private static final int DISTANCE_DRAW_SNAG = 20; - - private static final int ANIMATION_STATE_STARTING = 1; - private static final int ANIMATION_STATE_RUNNING = 2; - private static final int ANIMATION_STATE_DONE = 3; - - private static final int ANIMATION_TYPE_SCALE = 1; - - private float mAnimationFrom; - private float mAnimationTo; - private int mAnimationDuration; - private long mAnimationStartTime; - private int mAnimationType; - private int mAnimationState = ANIMATION_STATE_DONE; - - private InputMethodManager mInputMethodManager; + DragController mDragController; /** * Used to create a new DragLayer from XML. @@ -156,478 +51,24 @@ public class DragLayer extends FrameLayout implements DragController { */ public DragLayer(Context context, AttributeSet attrs) { super(context, attrs); - - final int srcColor = context.getResources().getColor(R.color.delete_color_filter); - mTrashPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP)); - - // Make estimated paint area in gray - int snagColor = context.getResources().getColor(R.color.snag_callout_color); - mEstimatedPaint.setColor(snagColor); - mEstimatedPaint.setStrokeWidth(3); - mEstimatedPaint.setAntiAlias(true); - } - public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) { - if (PROFILE_DRAWING_DURING_DRAG) { - android.os.Debug.startMethodTracing("Launcher"); - } - - // Hide soft keyboard, if visible - if (mInputMethodManager == null) { - mInputMethodManager = (InputMethodManager) - getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - } - mInputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); - - if (mListener != null) { - mListener.onDragStart(v, source, dragInfo, dragAction); - } - - Rect r = mDragRect; - r.set(v.getScrollX(), v.getScrollY(), 0, 0); - - offsetDescendantRectToMyCoords(v, r); - mTouchOffsetX = mLastMotionX - r.left; - mTouchOffsetY = mLastMotionY - r.top; - - v.clearFocus(); - v.setPressed(false); - - boolean willNotCache = v.willNotCacheDrawing(); - v.setWillNotCacheDrawing(false); - - // Reset the drawing cache background color to fully transparent - // for the duration of this operation - int color = v.getDrawingCacheBackgroundColor(); - v.setDrawingCacheBackgroundColor(0); - - if (color != 0) { - v.destroyDrawingCache(); - } - v.buildDrawingCache(); - Bitmap viewBitmap = v.getDrawingCache(); - int width = viewBitmap.getWidth(); - int height = viewBitmap.getHeight(); - - mTriggerWidth = width * 2 / 3; - mTriggerHeight = height * 2 / 3; - - Matrix scale = new Matrix(); - float scaleFactor = v.getWidth(); - scaleFactor = (scaleFactor + DRAG_SCALE) /scaleFactor; - scale.setScale(scaleFactor, scaleFactor); - - mAnimationTo = 1.0f; - mAnimationFrom = 1.0f / scaleFactor; - mAnimationDuration = ANIMATION_SCALE_UP_DURATION; - mAnimationState = ANIMATION_STATE_STARTING; - mAnimationType = ANIMATION_TYPE_SCALE; - - mDragBitmap = Bitmap.createBitmap(viewBitmap, 0, 0, width, height, scale, true); - v.destroyDrawingCache(); - v.setWillNotCacheDrawing(willNotCache); - v.setDrawingCacheBackgroundColor(color); - - final Bitmap dragBitmap = mDragBitmap; - mBitmapOffsetX = (dragBitmap.getWidth() - width) / 2; - mBitmapOffsetY = (dragBitmap.getHeight() - height) / 2; - - if (dragAction == DRAG_ACTION_MOVE) { - v.setVisibility(GONE); - } - - mDragPaint = null; - mDragging = true; - mShouldDrop = true; - mOriginator = v; - mDragSource = source; - mDragInfo = dragInfo; - - mVibrator.vibrate(VIBRATE_DURATION); - - mEnteredRegion = false; - - invalidate(); + public void setDragController(DragController controller) { + mDragController = controller; } - + @Override public boolean dispatchKeyEvent(KeyEvent event) { - return mDragging || super.dispatchKeyEvent(event); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - - if (mDragging && mDragBitmap != null) { - if (mAnimationState == ANIMATION_STATE_STARTING) { - mAnimationStartTime = SystemClock.uptimeMillis(); - mAnimationState = ANIMATION_STATE_RUNNING; - } - - if (mAnimationState == ANIMATION_STATE_RUNNING) { - float normalized = (float) (SystemClock.uptimeMillis() - mAnimationStartTime) / - mAnimationDuration; - if (normalized >= 1.0f) { - mAnimationState = ANIMATION_STATE_DONE; - } - normalized = Math.min(normalized, 1.0f); - final float value = mAnimationFrom + (mAnimationTo - mAnimationFrom) * normalized; - - switch (mAnimationType) { - case ANIMATION_TYPE_SCALE: - final Bitmap dragBitmap = mDragBitmap; - canvas.save(); - canvas.translate(mScrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX, - mScrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY); - canvas.translate((dragBitmap.getWidth() * (1.0f - value)) / 2, - (dragBitmap.getHeight() * (1.0f - value)) / 2); - canvas.scale(value, value); - canvas.drawBitmap(dragBitmap, 0.0f, 0.0f, mDragPaint); - canvas.restore(); - break; - } - } else { - // Only draw estimate drop "snag" when requested - if (DRAW_TARGET_SNAG && mDrawEstimated) { - canvas.drawLine(mDragCenter[0], mDragCenter[1], mEstimatedCenter[0], mEstimatedCenter[1], mEstimatedPaint); - canvas.drawCircle(mEstimatedCenter[0], mEstimatedCenter[1], 8, mEstimatedPaint); - } - - // Draw actual icon being dragged - canvas.drawBitmap(mDragBitmap, - mScrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX, - mScrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY, mDragPaint); - } - } - } - - private void endDrag() { - if (mDragging) { - mDragging = false; - if (mDragBitmap != null) { - mDragBitmap.recycle(); - } - if (mOriginator != null) { - mOriginator.setVisibility(VISIBLE); - } - if (mListener != null) { - mListener.onDragEnd(); - } - } + return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - final int action = ev.getAction(); - - final float x = ev.getX(); - final float y = ev.getY(); - - switch (action) { - case MotionEvent.ACTION_MOVE: - break; - - case MotionEvent.ACTION_DOWN: - // Remember location of down touch - mLastMotionX = x; - mLastMotionY = y; - mLastDropTarget = null; - break; - - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - if (mShouldDrop && drop(x, y)) { - mShouldDrop = false; - } - endDrag(); - break; - } - - return mDragging; + return mDragController.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { - if (!mDragging) { - return false; - } - - final int action = ev.getAction(); - final float x = ev.getX(); - final float y = ev.getY(); - - switch (action) { - case MotionEvent.ACTION_DOWN: - - // Remember where the motion event started - mLastMotionX = x; - mLastMotionY = y; - - if ((x < SCROLL_ZONE) || (x > getWidth() - SCROLL_ZONE)) { - mScrollState = SCROLL_WAITING_IN_ZONE; - postDelayed(mScrollRunnable, SCROLL_DELAY); - } else { - mScrollState = SCROLL_OUTSIDE_ZONE; - } - - break; - case MotionEvent.ACTION_MOVE: - final int scrollX = mScrollX; - final int scrollY = mScrollY; - - final float touchX = mTouchOffsetX; - final float touchY = mTouchOffsetY; - - final int offsetX = mBitmapOffsetX; - final int offsetY = mBitmapOffsetY; - - int left = (int) (scrollX + mLastMotionX - touchX - offsetX); - int top = (int) (scrollY + mLastMotionY - touchY - offsetY); - - final Bitmap dragBitmap = mDragBitmap; - final int width = dragBitmap.getWidth(); - final int height = dragBitmap.getHeight(); - - final Rect rect = mRect; - rect.set(left - 1, top - 1, left + width + 1, top + height + 1); - - mLastMotionX = x; - mLastMotionY = y; - - left = (int) (scrollX + x - touchX - offsetX); - top = (int) (scrollY + y - touchY - offsetY); - - // Invalidate current icon position - rect.union(left - 1, top - 1, left + width + 1, top + height + 1); - - mDragCenter[0] = rect.centerX(); - mDragCenter[1] = rect.centerY(); - - // Invalidate any old estimated location - if (DRAW_TARGET_SNAG && mDrawEstimated) { - rect.union(mEstimatedRect); - } - - final int[] coordinates = mDropCoordinates; - DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates); - if (dropTarget != null) { - if (mLastDropTarget == dropTarget) { - dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1], - (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo); - } else { - if (mLastDropTarget != null) { - mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1], - (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo); - } - dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1], - (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo); - } - } else { - if (mLastDropTarget != null) { - mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1], - (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo); - } - } - - // Render estimated drop "snag" only outside of width - mDrawEstimated = false; - if (DRAW_TARGET_SNAG && dropTarget != null) { - Rect foundEstimate = dropTarget.estimateDropLocation(mDragSource, - (int) (scrollX + mLastMotionX), (int) (scrollY + mLastMotionY), - (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo, mEstimatedRect); - - if (foundEstimate != null) { - mEstimatedCenter[0] = foundEstimate.centerX(); - mEstimatedCenter[1] = foundEstimate.centerY(); - - int deltaX = (int) Math.abs(mEstimatedCenter[0] - mDragCenter[0]); - int deltaY = (int) Math.abs(mEstimatedCenter[1] - mDragCenter[1]); - - if (deltaX > mTriggerWidth || deltaY > mTriggerHeight) { - mDrawEstimated = true; - } - } - } - - // Include new estimated area in invalidated rectangle - if (DRAW_TARGET_SNAG && mDrawEstimated) { - rect.union(mEstimatedRect); - } - invalidate(rect); - - mLastDropTarget = dropTarget; - - boolean inDragRegion = false; - if (mDragRegion != null) { - final RectF region = mDragRegion; - final boolean inRegion = region.contains(ev.getRawX(), ev.getRawY()); - if (!mEnteredRegion && inRegion) { - mDragPaint = mTrashPaint; - mEnteredRegion = true; - inDragRegion = true; - } else if (mEnteredRegion && !inRegion) { - mDragPaint = null; - mEnteredRegion = false; - } - } - - if (!inDragRegion && x < SCROLL_ZONE) { - if (mScrollState == SCROLL_OUTSIDE_ZONE) { - mScrollState = SCROLL_WAITING_IN_ZONE; - mScrollRunnable.setDirection(SCROLL_LEFT); - postDelayed(mScrollRunnable, SCROLL_DELAY); - } - } else if (!inDragRegion && x > getWidth() - SCROLL_ZONE) { - if (mScrollState == SCROLL_OUTSIDE_ZONE) { - mScrollState = SCROLL_WAITING_IN_ZONE; - mScrollRunnable.setDirection(SCROLL_RIGHT); - postDelayed(mScrollRunnable, SCROLL_DELAY); - } - } else { - if (mScrollState == SCROLL_WAITING_IN_ZONE) { - mScrollState = SCROLL_OUTSIDE_ZONE; - mScrollRunnable.setDirection(SCROLL_RIGHT); - removeCallbacks(mScrollRunnable); - } - } - - break; - case MotionEvent.ACTION_UP: - removeCallbacks(mScrollRunnable); - if (mShouldDrop) { - drop(x, y); - mShouldDrop = false; - } - endDrag(); - - break; - case MotionEvent.ACTION_CANCEL: - endDrag(); - } - - return true; - } - - private boolean drop(float x, float y) { - invalidate(); - - final int[] coordinates = mDropCoordinates; - DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates); - - if (dropTarget != null) { - dropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1], - (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo); - if (dropTarget.acceptDrop(mDragSource, coordinates[0], coordinates[1], - (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo)) { - dropTarget.onDrop(mDragSource, coordinates[0], coordinates[1], - (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo); - mDragSource.onDropCompleted((View) dropTarget, true); - return true; - } else { - mDragSource.onDropCompleted((View) dropTarget, false); - return true; - } - } - return false; - } - - DropTarget findDropTarget(int x, int y, int[] dropCoordinates) { - return findDropTarget(this, x, y, dropCoordinates); - } - - private DropTarget findDropTarget(ViewGroup container, int x, int y, int[] dropCoordinates) { - final Rect r = mDragRect; - final int count = container.getChildCount(); - final int scrolledX = x + container.getScrollX(); - final int scrolledY = y + container.getScrollY(); - final View ignoredDropTarget = mIgnoredDropTarget; - - for (int i = count - 1; i >= 0; i--) { - final View child = container.getChildAt(i); - if (child.getVisibility() == VISIBLE && child != ignoredDropTarget) { - child.getHitRect(r); - if (r.contains(scrolledX, scrolledY)) { - DropTarget target = null; - if (child instanceof ViewGroup) { - x = scrolledX - child.getLeft(); - y = scrolledY - child.getTop(); - target = findDropTarget((ViewGroup) child, x, y, dropCoordinates); - } - if (target == null) { - if (child instanceof DropTarget) { - // Only consider this child if they will accept - DropTarget childTarget = (DropTarget) child; - if (childTarget.acceptDrop(mDragSource, x, y, 0, 0, mDragInfo)) { - dropCoordinates[0] = x; - dropCoordinates[1] = y; - return (DropTarget) child; - } else { - return null; - } - } - } else { - return target; - } - } - } - } - - return null; - } - - public void setDragScoller(DragScroller scroller) { - mDragScroller = scroller; - } - - public void setDragListener(DragListener l) { - mListener = l; - } - - public void removeDragListener(DragListener l) { - mListener = null; - } - - /** - * Specifies the view that must be ignored when looking for a drop target. - * - * @param view The view that will not be taken into account while looking - * for a drop target. - */ - void setIgnoredDropTarget(View view) { - mIgnoredDropTarget = view; - } - - /** - * Specifies the delete region. - * - * @param region The rectangle in screen coordinates of the delete region. - */ - void setDeleteRegion(RectF region) { - mDragRegion = region; - } - - private class ScrollRunnable implements Runnable { - private int mDirection; - - ScrollRunnable() { - } - - public void run() { - if (mDragScroller != null) { - mDrawEstimated = false; - if (mDirection == SCROLL_LEFT) { - mDragScroller.scrollLeft(); - } else { - mDragScroller.scrollRight(); - } - mScrollState = SCROLL_OUTSIDE_ZONE; - } - } - - void setDirection(int direction) { - mDirection = direction; - } + return mDragController.onTouchEvent(ev); } } diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java index 3c0a09d32..7c6ca58ae 100644 --- a/src/com/android/launcher2/DragSource.java +++ b/src/com/android/launcher2/DragSource.java @@ -23,6 +23,6 @@ import android.view.View; * */ public interface DragSource { - void setDragger(DragController dragger); + void setDragController(DragController dragger); void onDropCompleted(View target, boolean success); } diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java new file mode 100644 index 000000000..911a6ce9f --- /dev/null +++ b/src/com/android/launcher2/DragView.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2008 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.launcher2; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Point; +import android.os.IBinder; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.KeyEvent; +import android.view.WindowManager; +import android.view.WindowManagerImpl; + +public class DragView extends View implements TweenCallback { + // Number of pixels to add to the dragged item for scaling. Should be even for pixel alignment. + private static final int DRAG_SCALE = 24; + + private Bitmap mBitmap; + private Paint mPaint; + private int mRegistrationX; + private int mRegistrationY; + + SymmetricalLinearTween mTween; + private float mScale; + private float mAnimationScale = 1.0f; + + private WindowManager.LayoutParams mLayoutParams; + private WindowManager mWindowManager; + + /** + * Construct the drag view. + *

+ * The registration point is the point inside our view that the touch events should + * be centered upon. + * + * @param context A context + * @param bitmap The view that we're dragging around. We scale it up when we draw it. + * @param registrationX The x coordinate of the registration point. + * @param registrationY The y coordinate of the registration point. + */ + public DragView(Context context, Bitmap bitmap, int registrationX, int registrationY) { + super(context); + + mWindowManager = WindowManagerImpl.getDefault(); + + mTween = new SymmetricalLinearTween(false, 110 /*ms duration*/, this); + + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + + Matrix scale = new Matrix(); + float scaleFactor = width; + scaleFactor = mScale = (scaleFactor + DRAG_SCALE) / scaleFactor; + scale.setScale(scaleFactor, scaleFactor); + + mBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, scale, true); + + // The point in our scaled bitmap that the touch events are located + mRegistrationX = registrationX + (DRAG_SCALE / 2); + mRegistrationY = registrationY + (DRAG_SCALE / 2); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSize = resolveSize(mBitmap.getWidth(), widthMeasureSpec); + int heightSize = resolveSize(mBitmap.getHeight(), heightMeasureSpec); + setMeasuredDimension(widthSize, heightSize); + } + + @Override + protected void onDraw(Canvas canvas) { + if (false) { + // for debugging + Paint p = new Paint(); + p.setStyle(Paint.Style.FILL); + p.setColor(0xaaffffff); + canvas.drawRect(0, 0, getWidth(), getHeight(), p); + } + float scale = mAnimationScale; + if (scale < 0.999f) { // allow for some float error + float width = mBitmap.getWidth(); + float offset = (width-(width*scale))/2; + canvas.translate(offset, offset); + canvas.scale(scale, scale); + } + canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mBitmap.recycle(); + } + + public void onTweenValueChanged(float value, float oldValue) { + mAnimationScale = (1.0f+((mScale-1.0f)*value))/mScale; + invalidate(); + } + + public void onTweenStarted() { + } + + public void onTweenFinished() { + } + + public void setPaint(Paint paint) { + mPaint = paint; + invalidate(); + } + + /** + * Create a window containing this view and show it. + * + * @param windowToken obtained from v.getWindowToken() from one of your views + * @param touchX the x coordinate the user touched in screen coordinates + * @param touchY the y coordinate the user touched in screen coordinates + */ + public void show(IBinder windowToken, int touchX, int touchY) { + WindowManager.LayoutParams lp; + int pixelFormat; + + pixelFormat = PixelFormat.TRANSLUCENT; + + lp = new WindowManager.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + touchX-mRegistrationX, touchY-mRegistrationY, + WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + /*| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM*/, + pixelFormat); +// lp.token = mStatusBarView.getWindowToken(); + lp.gravity = Gravity.LEFT | Gravity.TOP; + lp.token = windowToken; + lp.setTitle("DragView"); + mLayoutParams = lp; + + mWindowManager.addView(this, lp); + + mAnimationScale = 1.0f/mScale; + mTween.start(true); + } + + /** + * Move the window containing this view. + * + * @param touchX the x coordinate the user touched in screen coordinates + * @param touchY the y coordinate the user touched in screen coordinates + */ + void move(int touchX, int touchY) { + WindowManager.LayoutParams lp = mLayoutParams; + lp.x = touchX - mRegistrationX; + lp.y = touchY - mRegistrationY; + mWindowManager.updateViewLayout(this, lp); + } + + void remove() { + mWindowManager.removeView(this); + } +} + diff --git a/src/com/android/launcher2/DropTarget.java b/src/com/android/launcher2/DropTarget.java index e092e5095..72eb33094 100644 --- a/src/com/android/launcher2/DropTarget.java +++ b/src/com/android/launcher2/DropTarget.java @@ -30,18 +30,25 @@ public interface DropTarget { * @param source DragSource where the drag started * @param x X coordinate of the drop location * @param y Y coordinate of the drop location - * @param xOffset Horizontal offset with the object being dragged where the original touch happened - * @param yOffset Vertical offset with the object being dragged where the original touch happened + * @param xOffset Horizontal offset with the object being dragged where the original + * touch happened + * @param yOffset Vertical offset with the object being dragged where the original + * touch happened + * @param dragView The DragView that's being dragged around on screen. * @param dragInfo Data associated with the object being dragged * */ - void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo); + void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo); - void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo); + void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo); - void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo); + void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo); - void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo); + void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo); /** * Check if a drop action can occur at, or near, the requested location. @@ -55,10 +62,12 @@ public interface DropTarget { * original touch happened * @param yOffset Vertical offset with the object being dragged where the * original touch happened + * @param dragView The DragView that's being dragged around on screen. * @param dragInfo Data associated with the object being dragged * @return True if the drop will be accepted, false otherwise. */ - boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo); + boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo); /** * Estimate the surface area where this object would land if dropped at the @@ -71,11 +80,19 @@ public interface DropTarget { * original touch happened * @param yOffset Vertical offset with the object being dragged where the * original touch happened + * @param dragView The DragView that's being dragged around on screen. * @param dragInfo Data associated with the object being dragged * @param recycle {@link Rect} object to be possibly recycled. * @return Estimated area that would be occupied if object was dropped at * the given location. Should return null if no estimate is found, * or if this target doesn't provide estimations. */ - Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle); + Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo, Rect recycle); + + // These methods are implemented in Views + void getHitRect(Rect outRect); + void getLocationOnScreen(int[] loc); + int getLeft(); + int getTop(); } diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java index 6281ebf98..bc5f9fd3b 100644 --- a/src/com/android/launcher2/Folder.java +++ b/src/com/android/launcher2/Folder.java @@ -35,7 +35,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL OnItemClickListener, OnClickListener, View.OnLongClickListener { protected AbsListView mContent; - protected DragController mDragger; + protected DragController mDragController; protected Launcher mLauncher; @@ -98,7 +98,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL app = new ApplicationInfo(app); } - mDragger.startDrag(view, this, app, DragController.DRAG_ACTION_COPY); + mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY); mLauncher.closeFolder(this); mDragItem = app; @@ -109,8 +109,8 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL mCloneInfo = cloneInfo; } - public void setDragger(DragController dragger) { - mDragger = dragger; + public void setDragController(DragController dragController) { + mDragController = dragController; } public void onDropCompleted(View target, boolean success) { diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java index 1531538fb..85fc3a754 100644 --- a/src/com/android/launcher2/FolderIcon.java +++ b/src/com/android/launcher2/FolderIcon.java @@ -62,7 +62,7 @@ public class FolderIcon extends BubbleTextView implements DropTarget { } public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { final ItemInfo item = (ItemInfo) dragInfo; final int itemType = item.itemType; return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || @@ -70,11 +70,13 @@ public class FolderIcon extends BubbleTextView implements DropTarget { && item.container != mInfo.id; } - public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle) { + public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo, Rect recycle) { return null; } - public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { final ApplicationInfo item = (ApplicationInfo) dragInfo; // TODO: update open folder that is looking at this data mInfo.add(item); @@ -82,16 +84,16 @@ public class FolderIcon extends BubbleTextView implements DropTarget { } public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { setCompoundDrawablesWithIntrinsicBounds(null, mOpenIcon, null, null); } public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { } public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { setCompoundDrawablesWithIntrinsicBounds(null, mCloseIcon, null, null); } } diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 661fbdb77..759af285c 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -166,6 +166,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On private LayoutInflater mInflater; + private DragController mDragController; private DragLayer mDragLayer; private WallpaperView mWallpaperView; private Workspace mWorkspace; @@ -528,10 +529,14 @@ public final class Launcher extends Activity implements View.OnClickListener, On * Finds all the views we need and configure them properly. */ private void setupViews() { + mDragController = new DragController(this); + DragController dragController = mDragController; + mDragLayer = (DragLayer) findViewById(R.id.drag_layer); final DragLayer dragLayer = mDragLayer; + dragLayer.setDragController(dragController); - mWallpaperView = (WallpaperView) dragLayer.findViewById(R.id.wallpaper); + mWallpaperView = (WallpaperView) findViewById(R.id.wallpaper); final WallpaperView wallpaper = mWallpaperView; mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace); @@ -546,7 +551,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On mHandleIcon.setCrossFadeEnabled(true); workspace.setOnLongClickListener(this); - workspace.setDragger(dragLayer); + workspace.setDragController(dragController); workspace.setLauncher(this); workspace.setWallpaper(wallpaper); @@ -554,12 +559,16 @@ public final class Launcher extends Activity implements View.OnClickListener, On wallpaper.setScreenCount(workspace.getScreenCount()); deleteZone.setLauncher(this); - deleteZone.setDragController(dragLayer); + deleteZone.setDragController(dragController); deleteZone.setHandle(mHandleView); - // TODO dragLayer.setIgnoredDropTarget(grid); - dragLayer.setDragScoller(workspace); - dragLayer.setDragListener(deleteZone); + dragController.setDragScoller(workspace); + dragController.setDragListener(deleteZone); + dragController.setScrollView(dragLayer); + + // The order here is bottom to top. + dragController.addDropTarget(workspace); + dragController.addDropTarget(deleteZone); } /** @@ -1347,6 +1356,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On ViewGroup parent = (ViewGroup) folder.getParent(); if (parent != null) { parent.removeView(folder); + mDragController.removeDropTarget((DropTarget)folder); } folder.onClose(); } @@ -1545,10 +1555,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On } } - DragController getDragController() { - return mDragLayer; - } - /** * Launches the intent referred by the clicked shortcut. * @@ -1646,7 +1652,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On return; } - openFolder.setDragger(mDragLayer); + openFolder.setDragController(mDragController); openFolder.setLauncher(this); openFolder.bind(folderInfo); @@ -1703,11 +1709,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On return sModel; } - void closeAllApplications() { - // TODO mDrawer.close(); - mAllAppsDialog.dismiss(); - } - View getDrawerHandle() { return mHandleView; } @@ -1744,6 +1745,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On protected void onPrepareDialog(int id, Dialog dialog) { switch (id) { case DIALOG_ALL_APPS: + mAllAppsGrid.onPrepareDialog(); break; case DIALOG_CREATE_SHORTCUT: break; @@ -1886,8 +1888,11 @@ public final class Launcher extends Activity implements View.OnClickListener, On setContentView(R.layout.all_apps); AllAppsGridView grid = mAllAppsGrid = (AllAppsGridView)findViewById(R.id.all_apps); + DragLayer dragLayer = (DragLayer)findViewById(R.id.drag_layer); + dragLayer.setDragController(mDragController); + grid.setTextFilterEnabled(false); - // TODO grid.setDragger(dragLayer); + grid.setDragController(mDragController); grid.setLauncher(Launcher.this); } @@ -1930,7 +1935,11 @@ public final class Launcher extends Activity implements View.OnClickListener, On mWorkspace.hide(); } - private void closeAllAppsDialog(boolean animated) { + void showWorkspace() { + mWorkspace.show(); + } + + void closeAllAppsDialog(boolean animated) { if (mAllAppsDialog.isOpen) { if (animated) { // TODO mDrawer.animateClose(); diff --git a/src/com/android/launcher2/LiveFolderIcon.java b/src/com/android/launcher2/LiveFolderIcon.java index 4e1904102..1876f2e0c 100644 --- a/src/com/android/launcher2/LiveFolderIcon.java +++ b/src/com/android/launcher2/LiveFolderIcon.java @@ -54,23 +54,28 @@ public class LiveFolderIcon extends FolderIcon { } @Override - public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { return false; } @Override - public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { } @Override - public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { } @Override - public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { } @Override - public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { } } diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java index a5e90587e..1379be6d0 100644 --- a/src/com/android/launcher2/UserFolder.java +++ b/src/com/android/launcher2/UserFolder.java @@ -28,31 +28,36 @@ public class UserFolder extends Folder implements DropTarget { } public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { final ItemInfo item = (ItemInfo) dragInfo; final int itemType = item.itemType; return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) && item.container != mInfo.id; } - public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle) { + public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo, Rect recycle) { return null; } - public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { final ApplicationInfo item = (ApplicationInfo) dragInfo; //noinspection unchecked ((ArrayAdapter) mContent.getAdapter()).add((ApplicationInfo) dragInfo); LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, 0, 0); } - public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { } - public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { } - public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { } @Override diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 43a6f78cc..bb32e0299 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -90,7 +90,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private OnLongClickListener mLongClickListener; private Launcher mLauncher; - private DragController mDragger; + private DragController mDragController; /** * Cache of vacant cells, used during drag events and invalidated as needed. @@ -363,6 +363,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag if (!(child instanceof Folder)) { child.setOnLongClickListener(mLongClickListener); } + if (child instanceof DropTarget) { + mDragController.addDropTarget((DropTarget)child); + } } void addWidget(View view, Widget widget) { @@ -436,6 +439,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag if (!(child instanceof Folder)) { child.setOnLongClickListener(mLongClickListener); } + if (child instanceof DropTarget) { + mDragController.addDropTarget((DropTarget)child); + } } } @@ -512,6 +518,11 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } } + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mDragController.setWindowToken(getWindowToken()); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -854,7 +865,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag CellLayout current = ((CellLayout) getChildAt(mCurrentScreen)); current.onDragChild(child); - mDragger.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE); + mDragController.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE); invalidate(); } @@ -888,7 +899,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag onDropExternal(result[0], result[1], info, layout, insertAtFirst); } - public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, + DragView dragView, Object dragInfo) { final CellLayout cellLayout = getCurrentDropLayout(); if (source != this) { onDropExternal(x - xOffset, y - yOffset, dragInfo, cellLayout); @@ -914,16 +926,16 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { clearVacantCache(); } public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { } public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, - Object dragInfo) { + DragView dragView, Object dragInfo) { clearVacantCache(); } @@ -958,6 +970,10 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag cellLayout.addView(view, insertAtFirst ? 0 : -1); view.setOnLongClickListener(mLongClickListener); + if (view instanceof DropTarget) { + mDragController.addDropTarget((DropTarget)view); + } + mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell); cellLayout.onDropChild(view, mTargetCell); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); @@ -981,7 +997,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag * {@inheritDoc} */ public boolean acceptDrop(DragSource source, int x, int y, - int xOffset, int yOffset, Object dragInfo) { + int xOffset, int yOffset, DragView dragView, Object dragInfo) { final CellLayout layout = getCurrentDropLayout(); final CellLayout.CellInfo cellInfo = mDragInfo; final int spanX = cellInfo == null ? 1 : cellInfo.spanX; @@ -999,7 +1015,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag * {@inheritDoc} */ public Rect estimateDropLocation(DragSource source, int x, int y, - int xOffset, int yOffset, Object dragInfo, Rect recycle) { + int xOffset, int yOffset, DragView dragView, Object dragInfo, Rect recycle) { final CellLayout layout = getCurrentDropLayout(); final CellLayout.CellInfo cellInfo = mDragInfo; @@ -1047,8 +1063,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag mLauncher = launcher; } - public void setDragger(DragController dragger) { - mDragger = dragger; + public void setDragController(DragController dragController) { + mDragController = dragController; } public void onDropCompleted(View target, boolean success) { @@ -1056,6 +1072,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag if (target != this && mDragInfo != null) { final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen); cellLayout.removeView(mDragInfo.cell); + if (mDragInfo.cell instanceof DropTarget) { + mDragController.removeDropTarget((DropTarget)mDragInfo.cell); + } final Object tag = mDragInfo.cell.getTag(); Launcher.getModel().removeDesktopItem((ItemInfo) tag); } @@ -1247,7 +1266,11 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag childCount = childrenToRemove.size(); for (int j = 0; j < childCount; j++) { - layout.removeViewInLayout(childrenToRemove.get(j)); + View child = childrenToRemove.get(j); + layout.removeViewInLayout(child); + if (child instanceof DropTarget) { + mDragController.removeDropTarget((DropTarget)child); + } } if (childCount > 0) { -- cgit v1.2.3