summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
authorJoe Onorato <joeo@google.com>2010-10-10 11:26:02 -0700
committerPatrick Dubroy <dubroy@google.com>2010-10-13 12:01:04 -0700
commit4be866d3a1665aa2098cb5d38d535b1ad1aab6d6 (patch)
tree2013e9ad151f31aecae8af27a0a213438549fdb2 /src/com
parentb0b2e6f588367cf40a4270cca81af7d78f8e382e (diff)
downloadandroid_packages_apps_Trebuchet-4be866d3a1665aa2098cb5d38d535b1ad1aab6d6.tar.gz
android_packages_apps_Trebuchet-4be866d3a1665aa2098cb5d38d535b1ad1aab6d6.tar.bz2
android_packages_apps_Trebuchet-4be866d3a1665aa2098cb5d38d535b1ad1aab6d6.zip
fix 3029324: Implement new drag feedback
Add "shrinkwrap" icon outlines to visualize where the item will land
Diffstat (limited to 'src/com')
-rw-r--r--src/com/android/launcher2/CellLayout.java154
-rw-r--r--src/com/android/launcher2/HolographicOutlineHelper.java89
-rw-r--r--src/com/android/launcher2/InterruptibleInOutAnimator.java29
-rw-r--r--src/com/android/launcher2/Workspace.java102
4 files changed, 300 insertions, 74 deletions
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;
}