15c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng/*
25c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Copyright (C) 2012 Google Inc.
35c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Licensed to The Android Open Source Project.
45c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng *
55c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
65c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * you may not use this file except in compliance with the License.
75c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * You may obtain a copy of the License at
85c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng *
95c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng *
115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Unless required by applicable law or agreed to in writing, software
125c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
135c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * See the License for the specific language governing permissions and
155c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * limitations under the License.
165c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng */
175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
185c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengpackage com.android.deskclock.widget.swipeablelistview;
195c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
205c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.animation.Animator;
215c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.animation.AnimatorListenerAdapter;
225c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.animation.ObjectAnimator;
235c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.animation.ValueAnimator;
245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.animation.ValueAnimator.AnimatorUpdateListener;
255c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.content.Context;
265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.content.res.Resources;
275c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.graphics.RectF;
285c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.util.Log;
295c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.MotionEvent;
305c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.VelocityTracker;
315c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.View;
325c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.animation.LinearInterpolator;
335c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
345c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport com.android.deskclock.R;
355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
365c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng/**
375c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Copy of packages/apps/UnifiedEmail - com.android.mail.ui.SwipeHelper with changes.
385c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng */
395c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengpublic class SwipeHelper {
405c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    static final String TAG = "com.android.systemui.SwipeHelper";
415c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static final boolean DEBUG_INVALIDATE = false;
425c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static final boolean CONSTRAIN_SWIPE = true;
435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static final boolean FADE_OUT_DURING_SWIPE = true;
445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static final boolean LOG_SWIPE_DISMISS_VELOCITY = false; // STOPSHIP - DEBUG ONLY
465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public static final int X = 0;
485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public static final int Y = 1;
495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static int SWIPE_ESCAPE_VELOCITY = -1;
535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static int DEFAULT_ESCAPE_ANIMATION_DURATION;
545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static int MAX_ESCAPE_ANIMATION_DURATION;
555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static int MAX_DISMISS_VELOCITY;
565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static int SNAP_ANIM_LEN;
575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static int DISMISS_ANIMATION_DURATION;
585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static int SWIPE_SCROLL_SLOP;
595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static float MIN_SWIPE;
605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static float MIN_VERT;
615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static float MIN_LOCK;
625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
635c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public static float ALPHA_FADE_START = 0f; // fraction of thumbnail width
645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                                                 // where fade starts
655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    static final float ALPHA_FADE_END = 0.7f; // fraction of thumbnail width
665c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                                              // beyond which alpha->0
675c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private static final float FACTOR = 1.2f;
682a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng
692a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng    private static final int PROTECTION_PADDING = 50;
702a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng
71aba3c451dccd54617947628045367c65febdee6bChiao Cheng    private float mMinAlpha = 0.3f;
725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private float mPagingTouchSlop;
74af70181fffc83d61d949714b4893a37863e63c2eIsaac Katzenelson    private final Callback mCallback;
75af70181fffc83d61d949714b4893a37863e63c2eIsaac Katzenelson    private final int mSwipeDirection;
76af70181fffc83d61d949714b4893a37863e63c2eIsaac Katzenelson    private final VelocityTracker mVelocityTracker;
775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private float mInitialTouchPosX;
795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private boolean mDragging;
805c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private View mCurrView;
815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private View mCurrAnimView;
825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private boolean mCanCurrViewBeDimissed;
835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private float mDensityScale;
845c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private float mLastY;
855c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private float mInitialTouchPosY;
865c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
87aba3c451dccd54617947628045367c65febdee6bChiao Cheng    private float mStartAlpha;
882a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng    private boolean mProtected = false;
89aba3c451dccd54617947628045367c65febdee6bChiao Cheng
905c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public SwipeHelper(Context context, int swipeDirection, Callback callback, float densityScale,
915c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            float pagingTouchSlop) {
925c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mCallback = callback;
935c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mSwipeDirection = swipeDirection;
945c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mVelocityTracker = VelocityTracker.obtain();
955c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mDensityScale = densityScale;
965c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mPagingTouchSlop = pagingTouchSlop;
975c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        if (SWIPE_ESCAPE_VELOCITY == -1) {
985c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            Resources res = context.getResources();
995c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            SWIPE_ESCAPE_VELOCITY = res.getInteger(R.integer.swipe_escape_velocity);
1005c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            DEFAULT_ESCAPE_ANIMATION_DURATION = res.getInteger(R.integer.escape_animation_duration);
1015c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            MAX_ESCAPE_ANIMATION_DURATION = res.getInteger(R.integer.max_escape_animation_duration);
1025c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            MAX_DISMISS_VELOCITY = res.getInteger(R.integer.max_dismiss_velocity);
1035c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            SNAP_ANIM_LEN = res.getInteger(R.integer.snap_animation_duration);
1045c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            DISMISS_ANIMATION_DURATION = res.getInteger(R.integer.dismiss_animation_duration);
1055c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            SWIPE_SCROLL_SLOP = res.getInteger(R.integer.swipe_scroll_slop);
1065c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            MIN_SWIPE = res.getDimension(R.dimen.min_swipe);
1075c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            MIN_VERT = res.getDimension(R.dimen.min_vert);
1085c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            MIN_LOCK = res.getDimension(R.dimen.min_lock);
1095c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
1105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1125c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void setDensityScale(float densityScale) {
1135c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mDensityScale = densityScale;
1145c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1155c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1165c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void setPagingTouchSlop(float pagingTouchSlop) {
1175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mPagingTouchSlop = pagingTouchSlop;
1185c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1195c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1205c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private float getVelocity(VelocityTracker vt) {
1215c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return mSwipeDirection == X ? vt.getXVelocity() :
1225c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                vt.getYVelocity();
1235c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1255c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private ObjectAnimator createTranslationAnimation(View v, float newPos) {
1265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        ObjectAnimator anim = ObjectAnimator.ofFloat(v,
1275c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mSwipeDirection == X ? "translationX" : "translationY", newPos);
1285c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return anim;
1295c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1305c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1315c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private ObjectAnimator createDismissAnimation(View v, float newPos, int duration) {
1325c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        ObjectAnimator anim = createTranslationAnimation(v, newPos);
1335c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        anim.setInterpolator(sLinearInterpolator);
1345c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        anim.setDuration(duration);
1355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return anim;
1365c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1375c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1385c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private float getPerpendicularVelocity(VelocityTracker vt) {
1395c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return mSwipeDirection == X ? vt.getYVelocity() :
1405c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                vt.getXVelocity();
1415c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1425c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private void setTranslation(View v, float translate) {
1445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        if (mSwipeDirection == X) {
1455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            v.setTranslationX(translate);
1465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        } else {
1475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            v.setTranslationY(translate);
1485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
1495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private float getSize(View v) {
1525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return mSwipeDirection == X ? v.getMeasuredWidth() :
1535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                v.getMeasuredHeight();
1545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void setMinAlpha(float minAlpha) {
1575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mMinAlpha = minAlpha;
1585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private float getAlphaForOffset(View view) {
1615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        float viewSize = getSize(view);
1625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        final float fadeSize = ALPHA_FADE_END * viewSize;
163aba3c451dccd54617947628045367c65febdee6bChiao Cheng        float result = mStartAlpha;
1645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        float pos = view.getTranslationX();
1655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        if (pos >= viewSize * ALPHA_FADE_START) {
166aba3c451dccd54617947628045367c65febdee6bChiao Cheng            result = mStartAlpha - (pos - viewSize * ALPHA_FADE_START) / fadeSize;
167aba3c451dccd54617947628045367c65febdee6bChiao Cheng        } else if (pos < viewSize * (mStartAlpha - ALPHA_FADE_START)) {
168aba3c451dccd54617947628045367c65febdee6bChiao Cheng            result = mStartAlpha + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
1695c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
1705c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return Math.max(mMinAlpha, result);
1715c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    // invalidate the view's own bounds all the way up the view hierarchy
1745c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public static void invalidateGlobalRegion(View view) {
1755c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        invalidateGlobalRegion(
1765c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            view,
1775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
1785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1805c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    // invalidate a rectangle relative to the view's coordinate system all the way up the view
1815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    // hierarchy
1825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public static void invalidateGlobalRegion(View view, RectF childBounds) {
1835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        //childBounds.offset(view.getTranslationX(), view.getTranslationY());
1845c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        if (DEBUG_INVALIDATE)
1855c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            Log.v(TAG, "-------------");
1865c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        while (view.getParent() != null && view.getParent() instanceof View) {
1875c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            view = (View) view.getParent();
1885c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            view.getMatrix().mapRect(childBounds);
1895c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            view.invalidate((int) Math.floor(childBounds.left),
1905c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            (int) Math.floor(childBounds.top),
1915c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            (int) Math.ceil(childBounds.right),
1925c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            (int) Math.ceil(childBounds.bottom));
1935c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            if (DEBUG_INVALIDATE) {
1945c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
1955c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        + "," + (int) Math.floor(childBounds.top)
1965c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        + "," + (int) Math.ceil(childBounds.right)
1975c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        + "," + (int) Math.ceil(childBounds.bottom));
1985c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
1995c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
2005c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
2015c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
2025c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public boolean onInterceptTouchEvent(MotionEvent ev) {
2035c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        final int action = ev.getAction();
2045c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        switch (action) {
2055c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            case MotionEvent.ACTION_DOWN:
2065c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mLastY = ev.getY();
2075c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mDragging = false;
2085c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mCurrView = mCallback.getChildAtPosition(ev);
2095c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mVelocityTracker.clear();
2105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                if (mCurrView != null) {
2112a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng
2122a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    View button = mCurrView.findViewById(R.id.onoff);
2132a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng
2142a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    // Find raw top and left positions for button.
2152a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    int left = button.getLeft();
2162a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    int top = button.getTop();
2172a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    View parent = (View) button.getParent();
2182a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    while (parent != null) {
2192a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                        left += parent.getLeft();
2202a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                        top += parent.getTop();
2212a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                        if (parent.getParent() == parent.getRootView()) {
2222a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                            parent = null;
2232a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                        } else {
2242a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                            parent = (View) parent.getParent();
2252a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                        }
2262a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    }
2272a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng
2282a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    // Add protection.
2292a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    int bottom = top + button.getHeight() + PROTECTION_PADDING;
2302a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    top -= PROTECTION_PADDING;
2312a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    left -= PROTECTION_PADDING;
2322a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng
2332a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    float rawX = ev.getRawX();
2342a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    float rawY = ev.getRawY();
2352a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng
2362a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    // Check if we are in the protected no-op area.
2372a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    if (rawX > left && rawY > top && rawY < bottom) {
2382a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                        mProtected = true;
2392a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    } else {
2402a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                        mProtected = false;
2412a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng                    }
2422a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng
2435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    mCurrAnimView = mCallback.getChildContentView(mCurrView);
244aba3c451dccd54617947628045367c65febdee6bChiao Cheng                    mStartAlpha = mCurrAnimView.getAlpha();
2455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
2465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    mVelocityTracker.addMovement(ev);
2475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    mInitialTouchPosX = ev.getX();
2485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    mInitialTouchPosY = ev.getY();
2495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                }
2505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                break;
2515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            case MotionEvent.ACTION_MOVE:
2525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                if (mCurrView != null) {
2535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // Check the movement direction.
2545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    if (mLastY >= 0 && !mDragging) {
2555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        float currY = ev.getY();
2565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        float currX = ev.getX();
2575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        float deltaY = Math.abs(currY - mInitialTouchPosY);
2585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        float deltaX = Math.abs(currX - mInitialTouchPosX);
2595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        if (deltaY > SWIPE_SCROLL_SLOP && deltaY > (FACTOR * deltaX)) {
2605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            mLastY = ev.getY();
2615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            mCallback.onScroll();
2625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            return false;
2635c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        }
2645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    }
2655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    mVelocityTracker.addMovement(ev);
2665c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float pos = ev.getX();
2675c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float delta = pos - mInitialTouchPosX;
2685c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    if (Math.abs(delta) > mPagingTouchSlop) {
2695c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        mCallback.onBeginDrag(mCallback.getChildContentView(mCurrView));
2705c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        mDragging = true;
2715c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        mInitialTouchPosX = ev.getX() - mCurrAnimView.getTranslationX();
2725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        mInitialTouchPosY = ev.getY();
2735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    }
2745c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                }
2755c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mLastY = ev.getY();
2765c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                break;
2775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            case MotionEvent.ACTION_UP:
2785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            case MotionEvent.ACTION_CANCEL:
2795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mDragging = false;
2805c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mCurrView = null;
2815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mCurrAnimView = null;
2825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mLastY = -1;
2835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                break;
2845c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
2855c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return mDragging;
2865c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
2875c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
2885c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    /**
2895c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng     * @param view The view to be dismissed
2905c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng     * @param velocity The desired pixels/second speed at which the view should
2915c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng     *            move
2925c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng     */
2935c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private void dismissChild(final View view, float velocity) {
2945c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        final View animView = mCallback.getChildContentView(view);
2955c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
2965c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        float newPos = determinePos(animView, velocity);
2975c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        int duration = determineDuration(animView, newPos, velocity);
2985c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
2995c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
3005c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        ObjectAnimator anim = createDismissAnimation(animView, newPos, duration);
3015c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        anim.addListener(new AnimatorListenerAdapter() {
3025c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            @Override
3035c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            public void onAnimationEnd(Animator animation) {
3045c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mCallback.onChildDismissed(mCurrView);
3055c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                animView.setLayerType(View.LAYER_TYPE_NONE, null);
3065c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
3075c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        });
3085c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        anim.addUpdateListener(new AnimatorUpdateListener() {
3095c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            @Override
3105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            public void onAnimationUpdate(ValueAnimator animation) {
3115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
3125c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    animView.setAlpha(getAlphaForOffset(animView));
3135c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                }
3145c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                invalidateGlobalRegion(animView);
3155c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
3165c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        });
3175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        anim.start();
3185c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
3195c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
3205c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private int determineDuration(View animView, float newPos, float velocity) {
3215c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        int duration = MAX_ESCAPE_ANIMATION_DURATION;
3225c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        if (velocity != 0) {
3235c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            duration = Math
3245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    .min(duration,
3255c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            (int) (Math.abs(newPos - animView.getTranslationX()) * 1000f / Math
3265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                                    .abs(velocity)));
3275c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        } else {
3285c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
3295c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
3305c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return duration;
3315c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
3325c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
3335c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private float determinePos(View animView, float velocity) {
3345c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        float newPos = 0;
3355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        if (velocity < 0 || (velocity == 0 && animView.getTranslationX() < 0)
3365c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        // if we use the Menu to dismiss an item in landscape, animate up
3375c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                || (velocity == 0 && animView.getTranslationX() == 0 && mSwipeDirection == Y)) {
3385c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            newPos = -getSize(animView);
3395c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        } else {
3405c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            newPos = getSize(animView);
3415c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
3425c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return newPos;
3435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
3445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
3455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void snapChild(final View view, float velocity) {
3465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        final View animView = mCallback.getChildContentView(view);
3475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
3485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        ObjectAnimator anim = createTranslationAnimation(animView, 0);
3495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        int duration = SNAP_ANIM_LEN;
3505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        anim.setDuration(duration);
3515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        anim.addUpdateListener(new AnimatorUpdateListener() {
3525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            @Override
3535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            public void onAnimationUpdate(ValueAnimator animation) {
3545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
3555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    animView.setAlpha(getAlphaForOffset(animView));
3565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                }
3575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                invalidateGlobalRegion(animView);
3585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
3595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        });
3605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        anim.addListener(new Animator.AnimatorListener() {
3615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            @Override
3625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            public void onAnimationStart(Animator animation) {
3635c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
3645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            @Override
3655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            public void onAnimationEnd(Animator animation) {
366aba3c451dccd54617947628045367c65febdee6bChiao Cheng                animView.setAlpha(mStartAlpha);
3675c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mCallback.onDragCancelled(mCurrView);
3685c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
3695c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            @Override
3705c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            public void onAnimationCancel(Animator animation) {
3715c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
3725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            @Override
3735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            public void onAnimationRepeat(Animator animation) {
3745c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
3755c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        });
3765c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        anim.start();
3775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
3785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
3795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public boolean onTouchEvent(MotionEvent ev) {
3802a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng        if (!mDragging || mProtected) {
3815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            return false;
3825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
3835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mVelocityTracker.addMovement(ev);
3845c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        final int action = ev.getAction();
3855c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        switch (action) {
3865c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            case MotionEvent.ACTION_OUTSIDE:
3875c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            case MotionEvent.ACTION_MOVE:
3885c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                if (mCurrView != null) {
3895c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float deltaX = ev.getX() - mInitialTouchPosX;
3905c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float deltaY = Math.abs(ev.getY() - mInitialTouchPosY);
3915c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // If the user has gone vertical and not gone horizontalish AT
3925c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // LEAST minBeforeLock, switch to scroll. Otherwise, cancel
3935c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // the swipe.
3945c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    if (!mDragging && deltaY > MIN_VERT && (Math.abs(deltaX)) < MIN_LOCK
3955c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            && deltaY > (FACTOR * Math.abs(deltaX))) {
3965c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        mCallback.onScroll();
3975c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        return false;
3985c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    }
3995c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float minDistance = MIN_SWIPE;
4005c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    if (Math.abs(deltaX) < minDistance) {
4015c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        // Don't start the drag until at least X distance has
4025c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        // occurred.
4035c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        return true;
4045c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    }
4055c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // don't let items that can't be dismissed be dragged more
4065c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // than maxScrollDistance
4075c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
4085c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        float size = getSize(mCurrAnimView);
4095c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        float maxScrollDistance = 0.15f * size;
4105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        if (Math.abs(deltaX) >= size) {
4115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            deltaX = deltaX > 0 ? maxScrollDistance : -maxScrollDistance;
4125c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        } else {
4135c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            deltaX = maxScrollDistance
4145c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                                    * (float) Math.sin((deltaX / size) * (Math.PI / 2));
4155c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        }
4165c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    }
4175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    setTranslation(mCurrAnimView, deltaX);
4185c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) {
4195c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        mCurrAnimView.setAlpha(getAlphaForOffset(mCurrAnimView));
4205c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    }
4215c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    invalidateGlobalRegion(mCallback.getChildContentView(mCurrView));
4225c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                }
4235c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                break;
4245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            case MotionEvent.ACTION_UP:
4255c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            case MotionEvent.ACTION_CANCEL:
4265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                if (mCurrView != null) {
4275c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float maxVelocity = MAX_DISMISS_VELOCITY * mDensityScale;
4285c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, maxVelocity);
4295c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale;
4305c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float velocity = getVelocity(mVelocityTracker);
4315c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
4325c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4335c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // Decide whether to dismiss the current view
4345c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // Tweak constants below as required to prevent erroneous
4355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // swipe/dismiss
4365c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float translation = Math.abs(mCurrAnimView.getTranslationX());
4375c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    float currAnimViewSize = getSize(mCurrAnimView);
4385c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // Long swipe = translation of .4 * width
4395c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH
440aba3c451dccd54617947628045367c65febdee6bChiao Cheng                            && translation > 0.4 * currAnimViewSize;
4415c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // Fast swipe = > escapeVelocity and translation of .1 *
4425c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    // width
4435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity)
4445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            && (Math.abs(velocity) > Math.abs(perpendicularVelocity))
4455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            && (velocity > 0) == (mCurrAnimView.getTranslationX() > 0)
4465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            && translation > 0.05 * currAnimViewSize;
4475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    if (LOG_SWIPE_DISMISS_VELOCITY) {
4485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        Log.v(TAG, "Swipe/Dismiss: " + velocity + "/" + escapeVelocity + "/"
4495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                                + perpendicularVelocity + ", x: " + translation + "/"
4505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                                + currAnimViewSize);
4515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    }
4525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    boolean dismissChild = mCallback.canChildBeDismissed(mCurrView)
4545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                            && (childSwipedFastEnough || childSwipedFarEnough);
4555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    if (dismissChild) {
4575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f);
4585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    } else {
4595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                        snapChild(mCurrView, velocity);
4605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                    }
4615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                }
4625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                break;
4635c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
4645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return true;
4655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
4665c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4675c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public interface Callback {
4685c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        View getChildAtPosition(MotionEvent ev);
4695c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4705c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        View getChildContentView(View v);
4715c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        void onScroll();
4735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4745c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        boolean canChildBeDismissed(View v);
4755c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4765c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        void onBeginDrag(View v);
4775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        void onChildDismissed(View v);
4795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4805c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        void onDragCancelled(View v);
4815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
4825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
4835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng}
484