Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f796309c authored by Hongwei Wang's avatar Hongwei Wang
Browse files

Refactor Drag Shadow

Bug: 10759985
Bug: 10686781
Change-Id: I8f6446ffe1e882c39c38e61c21a60561d91d1e2e
parent 2131091c
Loading
Loading
Loading
Loading
+119 −15
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@ package com.android.dialer.list;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
@@ -63,6 +66,20 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba
    private boolean mIsDragScrollerRunning = false;
    private int mTouchDownForDragStartX;
    private int mTouchDownForDragStartY;
    private Bitmap mDragShadowBitmap;

    // X and Y offsets inside the item from where the user grabbed to the
    // child's left coordinate. This is used to aid in the drawing of the drag shadow.
    private int mTouchOffsetToChildLeft;
    private int mTouchOffsetToChildTop;

    private int mDragShadowLeft;
    private int mDragShadowTop;
    private int mDragShadowWidth;
    private int mDragShadowHeight;

    private final int DRAG_SHADOW_ALPHA = 180;
    private final Paint mPaint = new Paint();

    /**
     * {@link #mTopScrollBound} and {@link mBottomScrollBound} will be
@@ -97,6 +114,7 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba
        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this,
                mDensityScale, mTouchSlop);
        setItemsCanFocus(true);
        mPaint.setAlpha(DRAG_SHADOW_ALPHA);
    }

    @Override
@@ -206,7 +224,9 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba
        final int eY = (int) event.getY();
        switch (action) {
            case DragEvent.ACTION_DRAG_STARTED:
                handleDragStarted(mTouchDownForDragStartX, mTouchDownForDragStartY);
                if (!handleDragStarted(mTouchDownForDragStartX, mTouchDownForDragStartY)) {
                    return false;
                };
                break;
            case DragEvent.ACTION_DRAG_LOCATION:
                mLastDragY = eY;
@@ -232,7 +252,7 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba
                mScrollHandler.removeCallbacks(mDragScroller);
                mIsDragScrollerRunning = false;
                if (action != DragEvent.ACTION_DRAG_EXITED) {
                    handleDragFinished();
                    handleDragFinished(eX, eY);
                }
                break;
            default:
@@ -242,6 +262,15 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba
        return true;
    }

    @Override
    public void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        // Draw the drag shadow at its last known location if the drag shadow exists.
        if (mDragShadowBitmap != null) {
            canvas.drawBitmap(mDragShadowBitmap, mDragShadowLeft, mDragShadowTop, mPaint);
        }
    }

    /**
     * Find the view under the pointer.
     */
@@ -263,34 +292,109 @@ public class PhoneFavoriteListView extends ListView implements SwipeHelperCallba
        }
    }

    private void handleDragStarted(int x, int y) {
    /**
     * @return True if the drag is started.
     */
    private boolean handleDragStarted(int x, int y) {
        final View child = getViewAtPosition(x, y);
        if (child instanceof ContactTileRow) {
        if (!(child instanceof ContactTileRow)) {
            // Bail early.
            return false;
        }

        final ContactTileRow tile = (ContactTileRow) child;
        final int itemIndex = tile.getItemIndex(x, y);
        if (itemIndex != -1 && mOnDragDropListener != null) {
                mOnDragDropListener.onDragStarted(itemIndex);
            final PhoneFavoriteTileView tileView =
                    (PhoneFavoriteTileView) tile.getViewAtPosition(x, y);
            mDragShadowBitmap = createDraggedChildBitmap(tileView);
            if (mDragShadowBitmap == null) {
                return false;
            }

            if (tileView instanceof PhoneFavoriteRegularRowView) {
                mDragShadowLeft = tile.getLeft();
                mDragShadowTop = tile.getTop();
            } else {
                // Square tile is relative to the contact tile,
                // and contact tile is relative to this list view.
                mDragShadowLeft = tileView.getLeft() + tileView.getParentRow().getLeft();
                mDragShadowTop = tileView.getTop() + tileView.getParentRow().getTop();
            }
            mDragShadowWidth = tileView.getWidth();
            mDragShadowHeight = tileView.getHeight();

            // x and y passed in are the coordinates of where the user has touched down, calculate
            // the offset to the top left coordinate of the dragged child.  This will be used for
            // drawing the drag shadow.
            mTouchOffsetToChildLeft = x - mDragShadowLeft;
            mTouchOffsetToChildTop = y - mDragShadowTop;

            // invalidate to trigger a redraw of the drag shadow.
            invalidate();

            mOnDragDropListener.onDragStarted(itemIndex);
        }

        return true;
    }

    private void handleDragHovered(int x, int y) {
        final View child = getViewAtPosition(x, y);
        if (child instanceof ContactTileRow) {
        if (!(child instanceof ContactTileRow)) {
            // Bail early.
            return;
        }

        // Update the drag shadow location.
        mDragShadowLeft = x - mTouchOffsetToChildLeft;
        mDragShadowTop = y - mTouchOffsetToChildTop;

        // invalidate to trigger a redraw of the drag shadow.
        invalidate();

        final ContactTileRow tile = (ContactTileRow) child;
        final int itemIndex = tile.getItemIndex(x, y);
        if (itemIndex != -1 && mOnDragDropListener != null) {
            mOnDragDropListener.onDragHovered(itemIndex);
        }
    }

    private void handleDragFinished(int x, int y) {
        // Update the drag shadow location.
        mDragShadowLeft = x - mTouchOffsetToChildLeft;
        mDragShadowTop = y - mTouchOffsetToChildTop;

        if (mDragShadowBitmap != null) {
            mDragShadowBitmap.recycle();
            mDragShadowBitmap = null;
        }

    private void handleDragFinished() {
        if (mOnDragDropListener != null) {
            mOnDragDropListener.onDragFinished();
        }
    }

    private Bitmap createDraggedChildBitmap(View view) {
        view.setDrawingCacheEnabled(true);
        final Bitmap cache = view.getDrawingCache();

        Bitmap bitmap = null;
        if (cache != null) {
            try {
                bitmap = cache.copy(Bitmap.Config.ARGB_8888, false);
            } catch (final OutOfMemoryError e) {
                Log.w(LOG_TAG, "Failed to copy bitmap from Drawing cache", e);
                bitmap = null;
            }
        }

        view.destroyDrawingCache();
        view.setDrawingCacheEnabled(false);

        return bitmap;
    }

    public interface OnDragDropListener {
        public void onDragStarted(int itemIndex);
        public void onDragHovered(int itemIndex);
+3 −2
Original line number Diff line number Diff line
@@ -92,16 +92,17 @@ public abstract class PhoneFavoriteTileView extends ContactTileView {
            public boolean onLongClick(View v) {
                setPressed(false);
                final PhoneFavoriteTileView view = (PhoneFavoriteTileView) v;
                // NOTE The drag shadow is handled in the ListView.
                if (view instanceof PhoneFavoriteRegularRowView) {
                    final ContactTileRow parent = (ContactTileRow) view.getParentRow();
                    // If the view is regular row, start drag the row view.
                    // Drag is not available for the item exceeds the PIN_LIMIT.
                    if (parent.getRegularRowItemIndex() < PhoneFavoritesTileAdapter.PIN_LIMIT) {
                        parent.startDrag(null, new View.DragShadowBuilder(parent), null, 0);
                        parent.startDrag(null, new View.DragShadowBuilder(), null, 0);
                    }
                } else {
                    // If the view is a tile view, start drag the tile.
                    view.startDrag(null, new View.DragShadowBuilder(view), null, 0);
                    view.startDrag(null, new View.DragShadowBuilder(), null, 0);
                }
                return true;
            }
+23 −17
Original line number Diff line number Diff line
@@ -634,6 +634,7 @@ public class PhoneFavoritesTileAdapter extends BaseAdapter implements
                        PinnedPositions.STAR_WHEN_PINNING, "true").build();
                // update the database here with the new pinned positions
                mContext.getContentResolver().update(pinUri, cv, null, null);
                notifyDataSetChanged();
            }
            mDraggedEntry = null;
        }
@@ -970,27 +971,32 @@ public class PhoneFavoritesTileAdapter extends BaseAdapter implements
            return mPosition;
        }

        @Override
        public View getChildAtPosition(MotionEvent ev) {
        /**
         * Find the view under the pointer.
         */
        public View getViewAtPosition(int x, int y) {
            // find the view under the pointer, accounting for GONE views
            final int count = getChildCount();
            final int touchX = (int) ev.getX();
            View slidingChild;
            View view;
            for (int childIdx = 0; childIdx < count; childIdx++) {
                slidingChild = getChildAt(childIdx);
                if (slidingChild.getVisibility() == GONE) {
                    continue;
                view = getChildAt(childIdx);
                if (x >= view.getLeft() && x <= view.getRight()) {
                    return view;
                }
            }
            return null;
        }
                if (touchX >= slidingChild.getLeft() && touchX <= slidingChild.getRight()) {
                    if (SwipeHelper.isSwipeable(slidingChild)) {

        @Override
        public View getChildAtPosition(MotionEvent ev) {
            final View view = getViewAtPosition((int) ev.getX(), (int) ev.getY());
            if (view != null &&
                    SwipeHelper.isSwipeable(view) &&
                    view.getVisibility() != GONE) {
                // If this view is swipable, then return it. If not, because the removal
                // dialog is currently showing, then return a null view, which will simply
                // be ignored by the swipe helper.
                        return slidingChild;
                    } else {
                        return null;
                    }
                }
                return view;
            }
            return null;
        }