From 4be866d3a1665aa2098cb5d38d535b1ad1aab6d6 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Sun, 10 Oct 2010 11:26:02 -0700 Subject: fix 3029324: Implement new drag feedback Add "shrinkwrap" icon outlines to visualize where the item will land --- src/com/android/launcher2/CellLayout.java | 154 ++++++++++++++------- .../launcher2/HolographicOutlineHelper.java | 89 ++++++++++-- .../launcher2/InterruptibleInOutAnimator.java | 29 +++- src/com/android/launcher2/Workspace.java | 102 +++++++++++++- 4 files changed, 300 insertions(+), 74 deletions(-) (limited to 'src') diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index d4a12fb64..5c1f57052 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -18,6 +18,8 @@ package com.android.launcher2; import com.android.launcher.R; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; @@ -25,13 +27,16 @@ import android.app.WallpaperManager; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.util.Log; import android.view.ContextMenu; import android.view.MotionEvent; import android.view.View; @@ -86,17 +91,15 @@ public class CellLayout extends ViewGroup implements Dimmable { private final Point mDragCenter = new Point(); - private Drawable mDragRectDrawable; - // These arrays are used to implement the drag visualization on x-large screens. - // They are used as circular arrays, indexed by mDragRectCurrent. - private Rect[] mDragRects = new Rect[8]; - private int[] mDragRectAlphas = new int[mDragRects.length]; - private InterruptibleInOutAnimator[] mDragRectAnims = - new InterruptibleInOutAnimator[mDragRects.length]; + // They are used as circular arrays, indexed by mDragOutlineCurrent. + private Point[] mDragOutlines = new Point[8]; + private int[] mDragOutlineAlphas = new int[mDragOutlines.length]; + private InterruptibleInOutAnimator[] mDragOutlineAnims = + new InterruptibleInOutAnimator[mDragOutlines.length]; // Used as an index into the above 3 arrays; indicates which is the most current value. - private int mDragRectCurrent = 0; + private int mDragOutlineCurrent = 0; private Drawable mCrosshairsDrawable = null; private InterruptibleInOutAnimator mCrosshairsAnimator = null; @@ -107,6 +110,8 @@ public class CellLayout extends ViewGroup implements Dimmable { private final WallpaperManager mWallpaperManager; + private boolean mDragging = false; + public CellLayout(Context context) { this(context, null); } @@ -164,7 +169,6 @@ public class CellLayout extends ViewGroup implements Dimmable { // Initialize the data structures used for the drag visualization. - mDragRectDrawable = res.getDrawable(R.drawable.rounded_rect_green); mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs); TimeInterpolator interp = new DecelerateInterpolator(2.5f); // Quint ease out @@ -179,8 +183,8 @@ public class CellLayout extends ViewGroup implements Dimmable { }); mCrosshairsAnimator.setInterpolator(interp); - for (int i = 0; i < mDragRects.length; i++) { - mDragRects[i] = new Rect(); + for (int i = 0; i < mDragOutlines.length; i++) { + mDragOutlines[i] = new Point(-1, -1); } // When dragging things around the home screens, we show a green outline of @@ -190,18 +194,45 @@ public class CellLayout extends ViewGroup implements Dimmable { final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime); final int fromAlphaValue = 0; final int toAlphaValue = res.getInteger(R.integer.config_dragOutlineMaxAlpha); - for (int i = 0; i < mDragRectAnims.length; i++) { + + for (int i = 0; i < mDragOutlineAlphas.length; i++) { + mDragOutlineAlphas[i] = fromAlphaValue; + } + + for (int i = 0; i < mDragOutlineAnims.length; i++) { final InterruptibleInOutAnimator anim = new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue); anim.setInterpolator(interp); + final int thisIndex = i; anim.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { - mDragRectAlphas[thisIndex] = (Integer) animation.getAnimatedValue(); - CellLayout.this.invalidate(mDragRects[thisIndex]); + final Bitmap outline = (Bitmap)anim.getTag(); + + // If an animation is started and then stopped very quickly, we can still + // get spurious updates we've cleared the tag. Guard against this. + if (outline == null) { + // Try to prevent it from continuing to run + animation.cancel(); + } else { + mDragOutlineAlphas[thisIndex] = (Integer) animation.getAnimatedValue(); + final int left = mDragOutlines[thisIndex].x; + final int top = mDragOutlines[thisIndex].y; + CellLayout.this.invalidate(left, top, + left + outline.getWidth(), top + outline.getHeight()); + } } }); - mDragRectAnims[i] = anim; + // The animation holds a reference to the drag outline bitmap as long is it's + // running. This way the bitmap can be GCed when the animations are complete. + anim.addListener(new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator animation) { + if ((Integer) anim.getAnimatedValue() == 0) { + anim.setTag(null); + } + } + }); + mDragOutlineAnims[i] = anim; } } @@ -270,14 +301,16 @@ public class CellLayout extends ViewGroup implements Dimmable { } x += mCellWidth + mWidthGap; } + } - for (int i = 0; i < mDragRects.length; i++) { - int alpha = mDragRectAlphas[i]; - if (alpha > 0) { - mDragRectDrawable.setAlpha(alpha); - mDragRectDrawable.setBounds(mDragRects[i]); - mDragRectDrawable.draw(canvas); - } + final Paint paint = new Paint(); + for (int i = 0; i < mDragOutlines.length; i++) { + final int alpha = mDragOutlineAlphas[i]; + if (alpha > 0) { + final Point p = mDragOutlines[i]; + final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag(); + paint.setAlpha(alpha); + canvas.drawBitmap(b, p.x, p.y, paint); } } } @@ -796,35 +829,40 @@ public class CellLayout extends ViewGroup implements Dimmable { result[1] = Math.max(0, result[1]); // Snap to top } - void visualizeDropLocation(View view, int originX, int originY, int spanX, int spanY) { - final int[] nearest = findNearestVacantArea(originX, originY, spanX, spanY, view, mDragCell); - mDragCenter.set(originX + (view.getWidth() / 2), originY + (view.getHeight() / 2)); + void visualizeDropLocation( + View v, Bitmap dragOutline, int originX, int originY, int spanX, int spanY) { + + final int[] nearest = findNearestVacantArea(originX, originY, spanX, spanY, v, mDragCell); + mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2)); if (nearest != null) { // Find the top left corner of the rect the object will occupy final int[] topLeft = mTmpPoint; cellToPoint(nearest[0], nearest[1], topLeft); - // Need to copy these, because the next call to cellToPoint will overwrite them - final int left = topLeft[0]; - final int top = topLeft[1]; + int left = topLeft[0]; + int top = topLeft[1]; - final Rect dragRect = mDragRects[mDragRectCurrent]; + if (v.getParent() instanceof CellLayout) { + LayoutParams lp = (LayoutParams) v.getLayoutParams(); + left += lp.leftMargin; + top += lp.topMargin; + } - if (dragRect.isEmpty() || left != dragRect.left || top != dragRect.top) { - // Now find the bottom right - final int[] bottomRight = mTmpPoint; - cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight); - bottomRight[0] += mCellWidth; - bottomRight[1] += mCellHeight; + // Offsets due to the size difference between the View and the dragOutline + left += (v.getWidth() - dragOutline.getWidth()) / 2; + top += (v.getHeight() - dragOutline.getHeight()) / 2; - final int oldIndex = mDragRectCurrent; - mDragRectCurrent = (oldIndex + 1) % mDragRects.length; + final int oldIndex = mDragOutlineCurrent; + final Point lastPoint = mDragOutlines[oldIndex]; + if (lastPoint.x != left || lastPoint.y != top) { + mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length; - mDragRects[mDragRectCurrent].set(left, top, bottomRight[0], bottomRight[1]); + mDragOutlines[mDragOutlineCurrent].set(left, top); - mDragRectAnims[oldIndex].animateOut(); - mDragRectAnims[mDragRectCurrent].animateIn(); + mDragOutlineAnims[oldIndex].animateOut(); + mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline); + mDragOutlineAnims[mDragOutlineCurrent].animateIn(); } } @@ -1035,20 +1073,29 @@ public class CellLayout extends ViewGroup implements Dimmable { * Called when drag has left this CellLayout or has been completed (successfully or not) */ void onDragExit() { - // Invalidate the drag data - mDragCell[0] = -1; - mDragCell[1] = -1; + // This can actually be called when we aren't in a drag, e.g. when adding a new + // item to this layout via the customize drawer. + // Guard against that case. + if (mDragging) { + mDragging = false; - setHover(false); + // Invalidate the drag data + mDragCell[0] = -1; + mDragCell[1] = -1; - // Fade out the drag indicators - if (mCrosshairsAnimator != null) { - mCrosshairsAnimator.animateOut(); - } + setHover(false); - mDragRectAnims[mDragRectCurrent].animateOut(); - mDragRectCurrent = (mDragRectCurrent + 1) % mDragRects.length; - mDragRects[mDragRectCurrent].setEmpty(); + // Fade out the drag indicators + if (mCrosshairsAnimator != null) { + mCrosshairsAnimator.animateOut(); + } + + final int prev = mDragOutlineCurrent; + mDragOutlineAnims[prev].animateOut(); + mDragOutlineCurrent = (prev + 1) % mDragOutlines.length; + mDragOutlines[mDragOutlineCurrent].set(-1, -1); + mDragOutlineAlphas[mDragOutlineCurrent] = 0; + } } /** @@ -1091,6 +1138,11 @@ public class CellLayout extends ViewGroup implements Dimmable { * or it may have begun on another layout. */ void onDragEnter(View dragView) { + if (mDragging) { +// Log.d(TAG, "Received onDragEnter while drag still active"); + } + mDragging = true; + // Fade in the drag indicators if (mCrosshairsAnimator != null) { mCrosshairsAnimator.animateIn(); diff --git a/src/com/android/launcher2/HolographicOutlineHelper.java b/src/com/android/launcher2/HolographicOutlineHelper.java index 9e61b79d0..ea4b01a4c 100644 --- a/src/com/android/launcher2/HolographicOutlineHelper.java +++ b/src/com/android/launcher2/HolographicOutlineHelper.java @@ -19,26 +19,42 @@ package com.android.launcher2; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; +import android.graphics.MaskFilter; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.TableMaskFilter; public class HolographicOutlineHelper { private final Paint mHolographicPaint = new Paint(); - private final Paint mExpensiveBlurPaint = new Paint(); + private final Paint mBlurPaint = new Paint(); private final Paint mErasePaint = new Paint(); - private static final BlurMaskFilter mThickOuterBlurMaskFilter = new BlurMaskFilter(6.0f, - BlurMaskFilter.Blur.OUTER); - private static final BlurMaskFilter mThinOuterBlurMaskFilter = new BlurMaskFilter(1.0f, - BlurMaskFilter.Blur.OUTER); - private static final BlurMaskFilter mThickInnerBlurMaskFilter = new BlurMaskFilter(4.0f, - BlurMaskFilter.Blur.NORMAL); + private static final BlurMaskFilter sLargeGlowBlurMaskFilter = new BlurMaskFilter( + 10.0f, BlurMaskFilter.Blur.OUTER); + private static final BlurMaskFilter sThickOuterBlurMaskFilter = new BlurMaskFilter( + 6.0f, BlurMaskFilter.Blur.OUTER); + private static final BlurMaskFilter sMediumOuterBlurMaskFilter = new BlurMaskFilter( + 2.0f, BlurMaskFilter.Blur.OUTER); + private static final BlurMaskFilter sThinOuterBlurMaskFilter = new BlurMaskFilter( + 1.0f, BlurMaskFilter.Blur.OUTER); + + private static final BlurMaskFilter sThickInnerBlurMaskFilter = new BlurMaskFilter( + 4.0f, BlurMaskFilter.Blur.NORMAL); + private static final BlurMaskFilter sThinInnerBlurMaskFilter = new BlurMaskFilter( + 1.0f, BlurMaskFilter.Blur.INNER); + + private static final MaskFilter sFineClipTable = TableMaskFilter.CreateClipTable(0, 20); + private static final MaskFilter sCoarseClipTable = TableMaskFilter.CreateClipTable(0, 200); + + private int[] mTempOffset = new int[2]; HolographicOutlineHelper() { mHolographicPaint.setFilterBitmap(true); mHolographicPaint.setAntiAlias(true); - mExpensiveBlurPaint.setFilterBitmap(true); + mBlurPaint.setFilterBitmap(true); + mBlurPaint.setAntiAlias(true); mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); mErasePaint.setFilterBitmap(true); mErasePaint.setAntiAlias(true); @@ -65,6 +81,51 @@ public class HolographicOutlineHelper { } } + void applyGlow(Bitmap bitmap, Canvas canvas, int color) { + mBlurPaint.setMaskFilter(sThickOuterBlurMaskFilter); + Bitmap glow = bitmap.extractAlpha(mBlurPaint, mTempOffset); + + // Use the clip table to make the glow heavier closer to the outline + mHolographicPaint.setMaskFilter(sCoarseClipTable); + mHolographicPaint.setAlpha(150); + mHolographicPaint.setColor(color); + canvas.drawBitmap(glow, mTempOffset[0], mTempOffset[1], mHolographicPaint); + glow.recycle(); + } + + /** + * Draws a solid outline around a bitmap, erasing the original pixels. + * + * @param bitmap The bitmap to modify + * @param canvas A canvas on the bitmap + * @param color The color to draw the outline and glow in + * @param removeOrig If true, punch out the original pixels to just leave the outline + */ + void applyExpensiveOuterOutline(Bitmap bitmap, Canvas canvas, int color, boolean removeOrig) { + Bitmap originalImage = null; + if (removeOrig) { + originalImage = bitmap.extractAlpha(); + } + + // Compute an outer blur on the original bitmap + mBlurPaint.setMaskFilter(sMediumOuterBlurMaskFilter); + Bitmap outline = bitmap.extractAlpha(mBlurPaint, mTempOffset); + + // Paint the blurred bitmap back into the canvas. Using the clip table causes any alpha + // pixels above a certain threshold to be rounded up to be fully opaque. This gives the + // effect of a thick outline, with a slight blur on the edge + mHolographicPaint.setColor(color); + mHolographicPaint.setMaskFilter(sFineClipTable); + canvas.drawBitmap(outline, mTempOffset[0], mTempOffset[1], mHolographicPaint); + outline.recycle(); + + if (removeOrig) { + // Finally, punch out the original pixels, leaving just the outline + canvas.drawBitmap(originalImage, 0, 0, mErasePaint); + originalImage.recycle(); + } + } + /** * Applies a more expensive and accurate outline to whatever is currently drawn in a specified * bitmap. @@ -72,18 +133,18 @@ public class HolographicOutlineHelper { void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, int outlineColor) { // calculate the outer blur first - mExpensiveBlurPaint.setMaskFilter(mThickOuterBlurMaskFilter); + mBlurPaint.setMaskFilter(sThickOuterBlurMaskFilter); int[] outerBlurOffset = new int[2]; - Bitmap thickOuterBlur = srcDst.extractAlpha(mExpensiveBlurPaint, outerBlurOffset); - mExpensiveBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter); + Bitmap thickOuterBlur = srcDst.extractAlpha(mBlurPaint, outerBlurOffset); + mBlurPaint.setMaskFilter(sThinOuterBlurMaskFilter); int[] thinOuterBlurOffset = new int[2]; - Bitmap thinOuterBlur = srcDst.extractAlpha(mExpensiveBlurPaint, thinOuterBlurOffset); + Bitmap thinOuterBlur = srcDst.extractAlpha(mBlurPaint, thinOuterBlurOffset); // calculate the inner blur srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT); - mExpensiveBlurPaint.setMaskFilter(mThickInnerBlurMaskFilter); + mBlurPaint.setMaskFilter(sThickInnerBlurMaskFilter); int[] thickInnerBlurOffset = new int[2]; - Bitmap thickInnerBlur = srcDst.extractAlpha(mExpensiveBlurPaint, thickInnerBlurOffset); + Bitmap thickInnerBlur = srcDst.extractAlpha(mBlurPaint, thickInnerBlurOffset); // mask out the inner blur srcDstCanvas.setBitmap(thickInnerBlur); diff --git a/src/com/android/launcher2/InterruptibleInOutAnimator.java b/src/com/android/launcher2/InterruptibleInOutAnimator.java index fb0728480..920aa43e4 100644 --- a/src/com/android/launcher2/InterruptibleInOutAnimator.java +++ b/src/com/android/launcher2/InterruptibleInOutAnimator.java @@ -16,6 +16,8 @@ package com.android.launcher2; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.util.Log; @@ -31,6 +33,10 @@ public class InterruptibleInOutAnimator extends ValueAnimator { private Object mOriginalFromValue; private Object mOriginalToValue; + private boolean mFirstRun = true; + + private Object mTag = null; + public InterruptibleInOutAnimator(long duration, Object fromValue, Object toValue) { super(duration, fromValue, toValue); mOriginalDuration = duration; @@ -38,14 +44,17 @@ public class InterruptibleInOutAnimator extends ValueAnimator { mOriginalToValue = toValue; } - private void animate(Object fromValue, Object toValue) { + private void animateTo(Object toValue) { // This only makes sense when it's running in the opposite direction, or stopped. setDuration(mOriginalDuration - getCurrentPlayTime()); - final Object startValue = isRunning() ? getAnimatedValue() : fromValue; + final Object startValue = mFirstRun ? mOriginalFromValue : getAnimatedValue(); cancel(); - setValues(startValue, toValue); - start(); + if (startValue != toValue) { + setValues(startValue, toValue); + start(); + mFirstRun = false; + } } /** @@ -54,7 +63,7 @@ public class InterruptibleInOutAnimator extends ValueAnimator { * direction and animate for a correspondingly shorter duration. */ public void animateIn() { - animate(mOriginalFromValue, mOriginalToValue); + animateTo(mOriginalToValue); } /** @@ -64,6 +73,14 @@ public class InterruptibleInOutAnimator extends ValueAnimator { * direction and animate for a correspondingly shorter duration. */ public void animateOut() { - animate(mOriginalToValue, mOriginalFromValue); + animateTo(mOriginalFromValue); + } + + public void setTag(Object tag) { + mTag = tag; + } + + public Object getTag() { + return mTag; } } diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 0d070488e..75e39e0c6 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -33,9 +33,12 @@ import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Rect; +import android.graphics.Region.Op; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.IBinder; @@ -136,6 +139,11 @@ public class Workspace extends SmoothPagedView private boolean mInScrollArea = false; + private HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper(); + private Bitmap mDragOutline = null; + private Rect mTempRect = new Rect(); + private int[] mTempXY = new int[2]; + /** * Used to inflate the Workspace from XML. * @@ -921,8 +929,70 @@ public class Workspace extends SmoothPagedView } } + /** + * Draw the View v into the given Canvas. + * + * @param v the view to draw + * @param destCanvas the canvas to draw on + * @param padding the horizontal and vertical padding to use when drawing + */ + private void drawDragView(View v, Canvas destCanvas, int padding) { + final Rect clipRect = mTempRect; + v.getDrawingRect(clipRect); + + // For a TextView, adjust the clip rect so that we don't include the text label + if (v instanceof TextView) { + final int iconHeight = ((TextView)v).getCompoundPaddingTop() - v.getPaddingTop(); + clipRect.bottom = clipRect.top + iconHeight; + } + + // Draw the View into the bitmap. + // The translate of scrollX and scrollY is necessary when drawing TextViews, because + // they set scrollX and scrollY to large values to achieve centered text + + destCanvas.save(); + destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2); + destCanvas.clipRect(clipRect, Op.REPLACE); + v.draw(destCanvas); + destCanvas.restore(); + } + + /** + * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. + * Responsibility for the bitmap is transferred to the caller. + */ + private Bitmap createDragOutline(View v, Canvas canvas, int padding) { + final int outlineColor = getResources().getColor(R.color.drag_outline_color); + final Bitmap b = Bitmap.createBitmap( + v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888); + + canvas.setBitmap(b); + drawDragView(v, canvas, padding); + mOutlineHelper.applyExpensiveOuterOutline(b, canvas, outlineColor, true); + + return b; + } + + /** + * Returns a new bitmap to show when the given View is being dragged around. + * Responsibility for the bitmap is transferred to the caller. + */ + private Bitmap createDragBitmap(View v, Canvas canvas, int padding) { + final int outlineColor = getResources().getColor(R.color.drag_outline_color); + final Bitmap b = Bitmap.createBitmap( + mDragOutline.getWidth(), mDragOutline.getHeight(), Bitmap.Config.ARGB_8888); + + canvas.setBitmap(b); + canvas.drawBitmap(mDragOutline, 0, 0, null); + drawDragView(v, canvas, padding); + mOutlineHelper.applyGlow(b, canvas, outlineColor); + + return b; + } + void startDrag(CellLayout.CellInfo cellInfo) { View child = cellInfo.cell; + final int blurPadding = 40; // Make sure the drag was started by a long press as opposed to a long click. if (!child.isInTouchMode()) { @@ -935,9 +1005,29 @@ public class Workspace extends SmoothPagedView CellLayout current = ((CellLayout) getChildAt(mCurrentPage)); current.onDragChild(child); - mDragController.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE); + + child.clearFocus(); + child.setPressed(false); + + final Canvas canvas = new Canvas(); + + // The outline is used to visualize where the item will land if dropped + mDragOutline = createDragOutline(child, canvas, blurPadding); + + // The drag bitmap follows the touch point around on the screen + final Bitmap b = createDragBitmap(child, canvas, blurPadding); + + final int bmpWidth = b.getWidth(); + final int bmpHeight = b.getHeight(); + child.getLocationOnScreen(mTempXY); + final int screenX = (int) mTempXY[0] + (child.getWidth() - bmpWidth) / 2; + final int screenY = (int) mTempXY[1] + (child.getHeight() - bmpHeight) / 2; + mDragController.startDrag(b, screenX, screenY, 0, 0, bmpWidth, bmpHeight, this, + child.getTag(), DragController.DRAG_ACTION_MOVE, null); + b.recycle(); + current.onDragEnter(child); - invalidate(); + child.setVisibility(View.GONE); } void addApplicationShortcut(ShortcutInfo info, int screen, int cellX, int cellY, @@ -1280,7 +1370,7 @@ public class Workspace extends SmoothPagedView int localOriginX = originX - (mDragTargetLayout.getLeft() - mScrollX); int localOriginY = originY - (mDragTargetLayout.getTop() - mScrollY); mDragTargetLayout.visualizeDropLocation( - child, localOriginX, localOriginY, item.spanX, item.spanY); + child, mDragOutline, localOriginX, localOriginY, item.spanX, item.spanY); } } } @@ -1320,6 +1410,8 @@ public class Workspace extends SmoothPagedView } // Drag from somewhere else + // NOTE: This can also be called when we are outside of a drag event, when we want + // to add an item to one of the workspace screens. private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout, boolean insertAtFirst) { int screen = indexOfChild(cellLayout); @@ -1481,6 +1573,10 @@ public class Workspace extends SmoothPagedView } } + if (mDragInfo != null) { + mDragInfo.cell.setVisibility(View.VISIBLE); + } + mDragOutline = null; mDragInfo = null; } -- cgit v1.2.3