SwipeHelper.java revision 814086db674d8eb298541b7e601e29c5c68e2074
178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands/*
278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands * Copyright (C) 2014 The Android Open Source Project
378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands *
478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands * Licensed under the Apache License, Version 2.0 (the "License");
578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands * you may not use this file except in compliance with the License.
678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands * You may obtain a copy of the License at
778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands *
878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands *      http://www.apache.org/licenses/LICENSE-2.0
978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands *
1078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands * Unless required by applicable law or agreed to in writing, software
1178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands * distributed under the License is distributed on an "AS IS" BASIS,
1278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands * See the License for the specific language governing permissions and
14f2d754bb382cba0bad2774144ddac84be5354d16Duncan Sands * limitations under the License.
15f2d754bb382cba0bad2774144ddac84be5354d16Duncan Sands */
1678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
1778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandspackage com.android.systemui.recents.views;
18f2d754bb382cba0bad2774144ddac84be5354d16Duncan Sands
1978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport android.animation.Animator;
2078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport android.animation.AnimatorListenerAdapter;
2178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport android.animation.ObjectAnimator;
2278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport android.animation.ValueAnimator;
2347d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sandsimport android.animation.ValueAnimator.AnimatorUpdateListener;
24905ff1ebc4f383088e6af6fc37504cd06ba62b57Dan Gohmanimport android.annotation.TargetApi;
2578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport android.os.Build;
2678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport android.util.DisplayMetrics;
2778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport android.view.MotionEvent;
2878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport android.view.VelocityTracker;
2978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport android.view.View;
3078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport android.view.animation.LinearInterpolator;
3178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport com.android.systemui.recents.Console;
3278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sandsimport com.android.systemui.recents.Constants;
3378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
3478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands/**
35475871a144eb604ddaf37503397ba0941442e5fbDan Gohman * This class facilitates swipe to dismiss. It defines an interface to be implemented by the
36475871a144eb604ddaf37503397ba0941442e5fbDan Gohman * by the class hosting the views that need to swiped, and, using this interface, handles touch
37e50ed30282bb5b4a9ed952580523f2dda16215acOwen Anderson * events and translates / fades / animates the view as it is dismissed.
3823b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson */
39475871a144eb604ddaf37503397ba0941442e5fbDan Gohmanpublic class SwipeHelper {
40e50ed30282bb5b4a9ed952580523f2dda16215acOwen Anderson    static final String TAG = "SwipeHelper";
4135ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen    private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
4278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private static final boolean CONSTRAIN_SWIPE = true;
4378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private static final boolean FADE_OUT_DURING_SWIPE = true;
4478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
4578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
4678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    public static final int X = 0;
4778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    public static final int Y = 1;
4878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
4978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
5078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
5178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
5278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private int DEFAULT_ESCAPE_ANIMATION_DURATION = 75; // ms
5335ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen    private int MAX_ESCAPE_ANIMATION_DURATION = 150; // ms
5435ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen    private int MAX_DISMISS_VELOCITY = 2000; // dp/sec
5578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
5678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
5778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    public static float ALPHA_FADE_START = 0.15f; // fraction of thumbnail width
5878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                                                 // where fade starts
5978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    static final float ALPHA_FADE_END = 0.65f; // fraction of thumbnail width
6035ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen                                              // beyond which alpha->0
6135ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen    private float mMinAlpha = 0f;
6278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
63f4e4629ee8c218f892ad8ae3e182fe40bc160895Duncan Sands    private float mPagingTouchSlop;
6478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    Callback mCallback;
65f2d754bb382cba0bad2774144ddac84be5354d16Duncan Sands    private int mSwipeDirection;
66f2d754bb382cba0bad2774144ddac84be5354d16Duncan Sands    private VelocityTracker mVelocityTracker;
67f2d754bb382cba0bad2774144ddac84be5354d16Duncan Sands
68f2d754bb382cba0bad2774144ddac84be5354d16Duncan Sands    private float mInitialTouchPos;
69f2d754bb382cba0bad2774144ddac84be5354d16Duncan Sands    private boolean mDragging;
70f4e4629ee8c218f892ad8ae3e182fe40bc160895Duncan Sands
7178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private View mCurrView;
7278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private boolean mCanCurrViewBeDimissed;
7335ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen    private float mDensityScale;
7435ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen
7578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    public boolean mAllowSwipeTowardsStart = true;
76aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang    public boolean mAllowSwipeTowardsEnd = true;
77aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang    private boolean mRtl;
78aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang
7923b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson    public SwipeHelper(int swipeDirection, Callback callback, float densityScale,
80aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang            float pagingTouchSlop) {
81aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang        mCallback = callback;
82aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang        mSwipeDirection = swipeDirection;
83aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang        mVelocityTracker = VelocityTracker.obtain();
84aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang        mDensityScale = densityScale;
85aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang        mPagingTouchSlop = pagingTouchSlop;
86aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang    }
87aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang
88aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang    public void setDensityScale(float densityScale) {
89aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang        mDensityScale = densityScale;
90aa9df0b0c3cef33514095bde2eedead986677955Mon P Wang    }
9178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
9278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    public void setPagingTouchSlop(float pagingTouchSlop) {
93f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman        mPagingTouchSlop = pagingTouchSlop;
94f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman    }
95f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman
9623b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson    public void cancelOngoingDrag() {
97f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman        if (mDragging) {
98f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman            if (mCurrView != null) {
99f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman                mCallback.onDragCancelled(mCurrView);
1002fb070bf5a34f3fae89beb8609c92abc1b1a2551Eli Friedman                setTranslation(mCurrView, 0);
101f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman                mCallback.onSnapBackCompleted(mCurrView);
1022fb070bf5a34f3fae89beb8609c92abc1b1a2551Eli Friedman                mCurrView = null;
103f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman            }
104f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman            mDragging = false;
105f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman        }
106f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman    }
1078c899ee031481dbece5f111379a274c848cb5902Duncan Sands
108f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman    public void resetTranslation(View v) {
109f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman        setTranslation(v, 0);
110f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman    }
111f10d3a7bcda97d28f9d325cb58cec7e17d7ed101Eli Friedman
11247d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands    private float getPos(MotionEvent ev) {
11347d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands        return mSwipeDirection == X ? ev.getX() : ev.getY();
11447d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands    }
11547d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands
11647d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands    private float getTranslation(View v) {
11747d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands        return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
11823b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson    }
11947d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands
120905ff1ebc4f383088e6af6fc37504cd06ba62b57Dan Gohman    private float getVelocity(VelocityTracker vt) {
121905ff1ebc4f383088e6af6fc37504cd06ba62b57Dan Gohman        return mSwipeDirection == X ? vt.getXVelocity() :
12247d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands                vt.getYVelocity();
12347d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands    }
12435ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen
12547d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands    private ObjectAnimator createTranslationAnimation(View v, float newPos) {
12647d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands        ObjectAnimator anim = ObjectAnimator.ofFloat(v,
12735ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen                mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
12847d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands        return anim;
12947d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands    }
13047d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands
13135ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen    private float getPerpendicularVelocity(VelocityTracker vt) {
13247d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands        return mSwipeDirection == X ? vt.getYVelocity() :
13347d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands                vt.getXVelocity();
13447d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands    }
13535ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen
13647d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands    private void setTranslation(View v, float translate) {
13747d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands        if (mSwipeDirection == X) {
13847d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands            v.setTranslationX(translate);
13947d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands        } else {
14047d9dcc584cdb7fd645ca1d5c2a0ce363570aeb7Duncan Sands            v.setTranslationY(translate);
14178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        }
14278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    }
143475871a144eb604ddaf37503397ba0941442e5fbDan Gohman
144475871a144eb604ddaf37503397ba0941442e5fbDan Gohman    private float getSize(View v) {
14578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        final DisplayMetrics dm = v.getContext().getResources().getDisplayMetrics();
14678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        return mSwipeDirection == X ? dm.widthPixels : dm.heightPixels;
14778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    }
14878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
14978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    public void setMinAlpha(float minAlpha) {
150475871a144eb604ddaf37503397ba0941442e5fbDan Gohman        mMinAlpha = minAlpha;
151475871a144eb604ddaf37503397ba0941442e5fbDan Gohman    }
1524a307ecce68f90e0eebf1ded52b947816cdc2304Duncan Sands
153f5aeb1a8e4cf272c7348376d185ef8d8267653e0Dan Gohman    float getAlphaForOffset(View view) {
154f5aeb1a8e4cf272c7348376d185ef8d8267653e0Dan Gohman        float viewSize = getSize(view);
1554a307ecce68f90e0eebf1ded52b947816cdc2304Duncan Sands        final float fadeSize = ALPHA_FADE_END * viewSize;
1564a307ecce68f90e0eebf1ded52b947816cdc2304Duncan Sands        float result = 1.0f;
1574a307ecce68f90e0eebf1ded52b947816cdc2304Duncan Sands        float pos = getTranslation(view);
1584a307ecce68f90e0eebf1ded52b947816cdc2304Duncan Sands        if (pos >= viewSize * ALPHA_FADE_START) {
1592bee0afb7d023e029975abf7d3157759fa797d37Dan Gohman            result = 1.0f - (pos - viewSize * ALPHA_FADE_START) / fadeSize;
1604a307ecce68f90e0eebf1ded52b947816cdc2304Duncan Sands        } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) {
1614a307ecce68f90e0eebf1ded52b947816cdc2304Duncan Sands            result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
162475871a144eb604ddaf37503397ba0941442e5fbDan Gohman        }
163475871a144eb604ddaf37503397ba0941442e5fbDan Gohman        result = Math.min(result, 1.0f);
164475871a144eb604ddaf37503397ba0941442e5fbDan Gohman        result = Math.max(result, 0f);
16578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        return Math.max(mMinAlpha, result);
16635ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen    }
16778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
16878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    /**
16978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands     * Determines whether the given view has RTL layout.
170e50ed30282bb5b4a9ed952580523f2dda16215acOwen Anderson     */
17123b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
17278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    public static boolean isLayoutRtl(View view) {
17335ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
17423b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson            return View.LAYOUT_DIRECTION_RTL == view.getLayoutDirection();
17578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        } else {
17678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            return false;
17778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        }
178475871a144eb604ddaf37503397ba0941442e5fbDan Gohman    }
17978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
18078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    public boolean onInterceptTouchEvent(MotionEvent ev) {
18178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        Console.log(Constants.Log.UI.TouchEvents,
18235ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen                "[SwipeHelper|interceptTouchEvent]",
18378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
184de06470330260f5937e7ca558f5f5b3e171f2ee5Dale Johannesen        final int action = ev.getAction();
18535ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen
18678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        switch (action) {
18735ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen            case MotionEvent.ACTION_DOWN:
18878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                mDragging = false;
18935ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen                mCurrView = mCallback.getChildAtPosition(ev);
19078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                mVelocityTracker.clear();
19178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                if (mCurrView != null) {
19278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                    mRtl = isLayoutRtl(mCurrView);
19378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                    mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
19478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                    mVelocityTracker.addMovement(ev);
195475871a144eb604ddaf37503397ba0941442e5fbDan Gohman                    mInitialTouchPos = getPos(ev);
196475871a144eb604ddaf37503397ba0941442e5fbDan Gohman                } else {
197ab09b7e8f34075c1759127a113f41bdf921f4034Duncan Sands                    mCanCurrViewBeDimissed = false;
19835ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen                }
19978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                break;
20078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            case MotionEvent.ACTION_MOVE:
20123b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson                if (mCurrView != null) {
202475871a144eb604ddaf37503397ba0941442e5fbDan Gohman                    mVelocityTracker.addMovement(ev);
203475871a144eb604ddaf37503397ba0941442e5fbDan Gohman                    float pos = getPos(ev);
20478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                    float delta = pos - mInitialTouchPos;
20578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                    if (Math.abs(delta) > mPagingTouchSlop) {
20678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                        mCallback.onBeginDrag(mCurrView);
20778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                        mDragging = true;
20878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                        mInitialTouchPos = pos - getTranslation(mCurrView);
20978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                    }
21035ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen                }
21178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                break;
21278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            case MotionEvent.ACTION_UP:
21378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            case MotionEvent.ACTION_CANCEL:
21478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                mDragging = false;
21535ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen                mCurrView = null;
21678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                break;
2177fb085871857134f8cbeb17499d4ab771ba8da42Duncan Sands        }
21835ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen        return mDragging;
21978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    }
22078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
22178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    /**
22278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands     * @param view The view to be dismissed
223825b72b0571821bf2d378749f69d6c4cfb52d2f9Owen Anderson     * @param velocity The desired pixels/second speed at which the view should move
22478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands     */
22578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private void dismissChild(final View view, float velocity) {
22678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
22778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        float newPos;
22878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        if (velocity < 0
22978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                || (velocity == 0 && getTranslation(view) < 0)
23078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                // if we use the Menu to dismiss an item in landscape, animate up
23178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                || (velocity == 0 && getTranslation(view) == 0 && mSwipeDirection == Y)) {
232475871a144eb604ddaf37503397ba0941442e5fbDan Gohman            newPos = -getSize(view);
23378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        } else {
23478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            newPos = getSize(view);
23521c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands        }
23623b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson        int duration = MAX_ESCAPE_ANIMATION_DURATION;
23721c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands        if (velocity != 0) {
23821c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands            duration = Math.min(duration,
239c460ae90019ddb19d4c07b2cd2fbaecfa7adf67dDale Johannesen                                (int) (Math.abs(newPos - getTranslation(view)) *
24021c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands                                        1000f / Math.abs(velocity)));
241c460ae90019ddb19d4c07b2cd2fbaecfa7adf67dDale Johannesen        } else {
242c460ae90019ddb19d4c07b2cd2fbaecfa7adf67dDale Johannesen            duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
24321c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands        }
24421c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands
24521c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands        ValueAnimator anim = createTranslationAnimation(view, newPos);
24621c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands        anim.setInterpolator(sLinearInterpolator);
24721c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands        anim.setDuration(duration);
24821c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands        anim.addListener(new AnimatorListenerAdapter() {
24921c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands            @Override
25021c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands            public void onAnimationEnd(Animator animation) {
25121c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands                mCallback.onChildDismissed(view);
25221c2972f7d24680f6475877a3398b7f8cf515b33Duncan Sands                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
253ae099d54428f4113f8a71c53314975fb8a8e8bbcDuncan Sands                    view.setAlpha(1.f);
25478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                }
25578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            }
25678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        });
25778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        anim.addUpdateListener(new AnimatorUpdateListener() {
258475871a144eb604ddaf37503397ba0941442e5fbDan Gohman            @Override
25935ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen            public void onAnimationUpdate(ValueAnimator animation) {
26078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
26178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                    view.setAlpha(getAlphaForOffset(view));
26278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                }
26378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            }
26478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        });
26578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        anim.start();
266e50ed30282bb5b4a9ed952580523f2dda16215acOwen Anderson    }
26723b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson
26878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    private void snapChild(final View view, float velocity) {
26978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
270475871a144eb604ddaf37503397ba0941442e5fbDan Gohman        ValueAnimator anim = createTranslationAnimation(view, 0);
27178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        int duration = SNAP_ANIM_LEN;
27278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        anim.setDuration(duration);
27378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        anim.addUpdateListener(new AnimatorUpdateListener() {
27478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            @Override
27578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            public void onAnimationUpdate(ValueAnimator animation) {
276a87008d90b7d894cfca53d407642acfd7be2af3cEvan Cheng                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
27735ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen                    view.setAlpha(getAlphaForOffset(view));
27878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                }
27978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            }
28078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        });
28178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        anim.addListener(new AnimatorListenerAdapter() {
28278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            @Override
28378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            public void onAnimationEnd(Animator animation) {
28478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
285475871a144eb604ddaf37503397ba0941442e5fbDan Gohman                    view.setAlpha(1.0f);
28678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                }
287e50ed30282bb5b4a9ed952580523f2dda16215acOwen Anderson                mCallback.onSnapBackCompleted(view);
28878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            }
289e50ed30282bb5b4a9ed952580523f2dda16215acOwen Anderson        });
29023b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson        anim.start();
29135ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen    }
29278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
293b1303d05a89972195de023fda432cc621375a27cBob Wilson    public boolean onTouchEvent(MotionEvent ev) {
294b1303d05a89972195de023fda432cc621375a27cBob Wilson        Console.log(Constants.Log.UI.TouchEvents,
295b1303d05a89972195de023fda432cc621375a27cBob Wilson                "[SwipeHelper|touchEvent]",
29678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
29778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
298475871a144eb604ddaf37503397ba0941442e5fbDan Gohman        if (!mDragging) {
29978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            if (!onInterceptTouchEvent(ev)) {
30078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                return mCanCurrViewBeDimissed;
30178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            }
302475871a144eb604ddaf37503397ba0941442e5fbDan Gohman        }
30378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
30478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        mVelocityTracker.addMovement(ev);
30578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        final int action = ev.getAction();
30678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        switch (action) {
30778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            case MotionEvent.ACTION_OUTSIDE:
30878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            case MotionEvent.ACTION_MOVE:
30978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                if (mCurrView != null) {
310a87008d90b7d894cfca53d407642acfd7be2af3cEvan Cheng                    float delta = getPos(ev) - mInitialTouchPos;
31123b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson                    setSwipeAmount(delta);
312a87008d90b7d894cfca53d407642acfd7be2af3cEvan Cheng                }
31378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                break;
31478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            case MotionEvent.ACTION_UP:
31535ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen            case MotionEvent.ACTION_CANCEL:
31678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                if (mCurrView != null) {
31778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands                    endSwipe(mVelocityTracker);
318475871a144eb604ddaf37503397ba0941442e5fbDan Gohman                }
319475871a144eb604ddaf37503397ba0941442e5fbDan Gohman                break;
32078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        }
321f5aeb1a8e4cf272c7348376d185ef8d8267653e0Dan Gohman        return true;
32278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    }
32378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
324d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang    private void setSwipeAmount(float amount) {
325d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        // don't let items that can't be dismissed be dragged more than
326e50ed30282bb5b4a9ed952580523f2dda16215acOwen Anderson        // maxScrollDistance
327d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        if (CONSTRAIN_SWIPE
32835ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen                && (!isValidSwipeDirection(amount) || !mCallback.canChildBeDismissed(mCurrView))) {
329d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang            float size = getSize(mCurrView);
330d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang            float maxScrollDistance = 0.15f * size;
331e50ed30282bb5b4a9ed952580523f2dda16215acOwen Anderson            if (Math.abs(amount) >= size) {
33223b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson                amount = amount > 0 ? maxScrollDistance : -maxScrollDistance;
333d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang            } else {
334d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang                amount = maxScrollDistance * (float) Math.sin((amount/size)*(Math.PI/2));
335d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang            }
336d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        }
337d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        setTranslation(mCurrView, amount);
338d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) {
33923b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson            float alpha = getAlphaForOffset(mCurrView);
3407fb085871857134f8cbeb17499d4ab771ba8da42Duncan Sands            mCurrView.setAlpha(alpha);
34135ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen        }
342d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang    }
343d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang
344d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang    private boolean isValidSwipeDirection(float amount) {
345d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        if (mSwipeDirection == X) {
346d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang            if (mRtl) {
347d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang                return (amount <= 0) ? mAllowSwipeTowardsEnd : mAllowSwipeTowardsStart;
348d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang            } else {
34935ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen                return (amount <= 0) ? mAllowSwipeTowardsStart : mAllowSwipeTowardsEnd;
35035ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen            }
35135ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen        }
35235ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen
35335ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen        // Vertical swipes are always valid.
354d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        return true;
355d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang    }
35635ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen
357d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang    private void endSwipe(VelocityTracker velocityTracker) {
358d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        float maxVelocity = MAX_DISMISS_VELOCITY * mDensityScale;
359d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        velocityTracker.computeCurrentVelocity(1000 /* px/sec */, maxVelocity);
36035ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen        float velocity = getVelocity(velocityTracker);
361e50ed30282bb5b4a9ed952580523f2dda16215acOwen Anderson        float perpendicularVelocity = getPerpendicularVelocity(velocityTracker);
362b10b5ac8d9da43ca2db61401a20af6b676c98438Duncan Sands        float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale;
363b10b5ac8d9da43ca2db61401a20af6b676c98438Duncan Sands        float translation = getTranslation(mCurrView);
364d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        // Decide whether to dismiss the current view
365d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
366d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang                Math.abs(translation) > 0.6 * getSize(mCurrView);
367e8d7230f480654cdb8ff1c3d0a38e1e9ab0bd55fDale Johannesen        boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
368d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang                (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
369d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang                (velocity > 0) == (translation > 0);
370a87008d90b7d894cfca53d407642acfd7be2af3cEvan Cheng
371d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang        boolean dismissChild = mCallback.canChildBeDismissed(mCurrView)
372d17c0302763cfd0b3f6657d2493147552762ac07Mon P Wang                && isValidSwipeDirection(translation)
373475871a144eb604ddaf37503397ba0941442e5fbDan Gohman                && (childSwipedFastEnough || childSwipedFarEnough);
374ab09b7e8f34075c1759127a113f41bdf921f4034Duncan Sands
37578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        if (dismissChild) {
37635ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen            // flingadingy
37778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands            dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f);
37878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        } else {
37923b9b19b1a5a00faa9fce0788155c7dbfd00bfb1Owen Anderson            // snappity
380475871a144eb604ddaf37503397ba0941442e5fbDan Gohman            mCallback.onDragCancelled(mCurrView);
381475871a144eb604ddaf37503397ba0941442e5fbDan Gohman            snapChild(mCurrView, velocity);
38278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        }
38378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    }
38478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
38578cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    public interface Callback {
38678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        View getChildAtPosition(MotionEvent ev);
38778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
38878cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        boolean canChildBeDismissed(View v);
389475871a144eb604ddaf37503397ba0941442e5fbDan Gohman
39078cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        void onBeginDrag(View v);
39178cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
39278cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        void onChildDismissed(View v);
39378cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands
39478cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        void onSnapBackCompleted(View v);
39535ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen
39678cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands        void onDragCancelled(View v);
39778cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands    }
39835ba3d463834f83e2bf8e8ad631ffc4d73a0203cDale Johannesen}
39978cd649ad326f79a1f8424ca2b63cea3239a9a52Duncan Sands