FileDocCategorySizeDatePackage
DragLayer.javaAPI DocAndroid 1.5 API18624Wed May 06 22:42:46 BST 2009com.android.launcher

DragLayer

public class DragLayer extends android.widget.FrameLayout implements DragController
A ViewGroup that coordinated dragging across its dscendants

Fields Summary
private static final int
SCROLL_DELAY
private static final int
SCROLL_ZONE
private static final int
VIBRATE_DURATION
private static final int
ANIMATION_SCALE_UP_DURATION
private static final boolean
PROFILE_DRAWING_DURING_DRAG
private static final float
DRAG_SCALE
private boolean
mDragging
private boolean
mShouldDrop
private float
mLastMotionX
private float
mLastMotionY
private android.graphics.Bitmap
mDragBitmap
The bitmap that is currently being dragged
private android.view.View
mOriginator
private int
mBitmapOffsetX
private int
mBitmapOffsetY
private float
mTouchOffsetX
X offset from where we touched on the cell to its upper-left corner
private float
mTouchOffsetY
Y offset from where we touched on the cell to its upper-left corner
private android.graphics.Rect
mDragRect
Utility rectangle
private DragSource
mDragSource
Where the drag originated
private Object
mDragInfo
The data associated with the object being dragged
private final android.graphics.Rect
mRect
private final int[]
mDropCoordinates
private final android.os.Vibrator
mVibrator
private DragListener
mListener
private DragScroller
mDragScroller
private static final int
SCROLL_OUTSIDE_ZONE
private static final int
SCROLL_WAITING_IN_ZONE
private static final int
SCROLL_LEFT
private static final int
SCROLL_RIGHT
private int
mScrollState
private ScrollRunnable
mScrollRunnable
private android.view.View
mIgnoredDropTarget
private android.graphics.RectF
mDragRegion
private boolean
mEnteredRegion
private DropTarget
mLastDropTarget
private final android.graphics.Paint
mTrashPaint
private android.graphics.Paint
mDragPaint
private static final int
ANIMATION_STATE_STARTING
private static final int
ANIMATION_STATE_RUNNING
private static final int
ANIMATION_STATE_DONE
private static final int
ANIMATION_TYPE_SCALE
private float
mAnimationFrom
private float
mAnimationTo
private int
mAnimationDuration
private long
mAnimationStartTime
private int
mAnimationType
private int
mAnimationState
private android.view.inputmethod.InputMethodManager
mInputMethodManager
Constructors Summary
public DragLayer(android.content.Context context, android.util.AttributeSet attrs)
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.


                                
         
        super(context, attrs);

        final int srcColor = context.getResources().getColor(R.color.delete_color_filter);
        mTrashPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP));
    
Methods Summary
protected voiddispatchDraw(android.graphics.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 {
                canvas.drawBitmap(mDragBitmap,
                        mScrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX,
                        mScrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY, mDragPaint);
            }
        }
    
public booleandispatchKeyEvent(android.view.KeyEvent event)

        return mDragging || super.dispatchKeyEvent(event);
    
private booleandrop(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;
    
private voidendDrag()

        if (mDragging) {
            mDragging = false;
            if (mDragBitmap != null) {
                mDragBitmap.recycle();
            }
            if (mOriginator != null) {
                mOriginator.setVisibility(VISIBLE);
            }
            if (mListener != null) {
                mListener.onDragEnd();
            }
        }
    
private DropTargetfindDropTarget(android.view.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) {
                            dropCoordinates[0] = x;
                            dropCoordinates[1] = y;
                            return (DropTarget) child;
                        }
                    } else {
                        return target;
                    }
                }
            }
        }

        return null;
    
DropTargetfindDropTarget(int x, int y, int[] dropCoordinates)

        return findDropTarget(this, x, y, dropCoordinates);
    
public booleanonInterceptTouchEvent(android.view.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;
    
public booleanonTouchEvent(android.view.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);

            rect.union(left - 1, top - 1, left + width + 1, top + height + 1);
            invalidate(rect);

            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);
                }
            }
            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;
    
public voidremoveDragListener(DragListener l)

        mListener = null;   
    
voidsetDeleteRegion(android.graphics.RectF region)
Specifies the delete region.

param
region The rectangle in screen coordinates of the delete region.

        mDragRegion = region;
    
public voidsetDragListener(DragListener l)

        mListener = l;
    
public voidsetDragScoller(DragScroller scroller)

        mDragScroller = scroller;
    
voidsetIgnoredDropTarget(android.view.View view)
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.

        mIgnoredDropTarget = view;
    
public voidstartDrag(android.view.View v, DragSource source, java.lang.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);
        v.buildDrawingCache();

        Bitmap viewBitmap = v.getDrawingCache();
        int width = viewBitmap.getWidth();
        int height = viewBitmap.getHeight();

        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);

        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();