107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka/*
207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * Copyright (C) 2011 The Android Open Source Project
307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka *
407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * Licensed under the Apache License, Version 2.0 (the "License");
507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * you may not use this file except in compliance with the License.
607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * You may obtain a copy of the License at
707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka *
807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka *      http://www.apache.org/licenses/LICENSE-2.0
907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka *
1007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * Unless required by applicable law or agreed to in writing, software
1107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * distributed under the License is distributed on an "AS IS" BASIS,
1207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * See the License for the specific language governing permissions and
1407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * limitations under the License.
1507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka */
1607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
1707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkapackage com.android.systemui;
1807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
1907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.Animator;
202f2022afa1eb85018368398bd150e9575fc099c9Chet Haaseimport android.animation.AnimatorListenerAdapter;
2107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.ObjectAnimator;
2207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.ValueAnimator;
2307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.ValueAnimator.AnimatorUpdateListener;
24eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandlerimport android.content.Context;
2507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.graphics.RectF;
26f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandlerimport android.os.Handler;
2707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.util.Log;
2807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.MotionEvent;
2907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.VelocityTracker;
3007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.View;
31f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandlerimport android.view.ViewConfiguration;
32de84f0e77ea2bf713d15c290264059a413c2486aJohn Spurlockimport android.view.accessibility.AccessibilityEvent;
33eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandlerimport android.view.animation.AnimationUtils;
34eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandlerimport android.view.animation.Interpolator;
35de84f0e77ea2bf713d15c290264059a413c2486aJohn Spurlockimport android.view.animation.LinearInterpolator;
3607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
376a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerpublic class SwipeHelper implements Gefingerpoken {
3807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    static final String TAG = "com.android.systemui.SwipeHelper";
3996f4818ef41141649337d4dee09f837594e93d09Daniel Sandler    private static final boolean DEBUG = false;
4007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private static final boolean DEBUG_INVALIDATE = false;
4107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
423cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private static final boolean CONSTRAIN_SWIPE = true;
433cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private static final boolean FADE_OUT_DURING_SWIPE = true;
443cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
4507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
4607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public static final int X = 0;
4707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public static final int Y = 1;
4807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
492f2022afa1eb85018368398bd150e9575fc099c9Chet Haase    private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
50eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler    private final Interpolator mFastOutLinearInInterpolator;
512f2022afa1eb85018368398bd150e9575fc099c9Chet Haase
5207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
530e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka    private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
540e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka    private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
550e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka    private int MAX_DISMISS_VELOCITY = 2000; // dp/sec
560e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
5707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
585d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    public static float SWIPE_PROGRESS_FADE_START = 0f; // fraction of thumbnail width
5907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                                                 // where fade starts
605d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    static final float SWIPE_PROGRESS_FADE_END = 0.5f; // fraction of thumbnail width
615d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                                              // beyond which swipe progress->0
625d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    private float mMinSwipeProgress = 0f;
635d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    private float mMaxSwipeProgress = 1f;
6407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
6507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float mPagingTouchSlop;
6607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private Callback mCallback;
67f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    private Handler mHandler;
6807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private int mSwipeDirection;
6907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private VelocityTracker mVelocityTracker;
7007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
7107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float mInitialTouchPos;
7207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private boolean mDragging;
7307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private View mCurrView;
743cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private View mCurrAnimView;
753cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private boolean mCanCurrViewBeDimissed;
7607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float mDensityScale;
7707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
78f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    private boolean mLongPressSent;
794247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler    private LongPressListener mLongPressListener;
80f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    private Runnable mWatchLongPress;
81469e96e206f8df44b32ce393f8d19f0cae730030Daniel Sandler    private long mLongPressTimeout;
82f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
834247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler    final private int[] mTmpPos = new int[2];
8419c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek    private int mFalsingThreshold;
8519c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek    private boolean mTouchAboveFalsingThreshold;
864247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler
87eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler    public SwipeHelper(int swipeDirection, Callback callback, Context context) {
8807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mCallback = callback;
89f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        mHandler = new Handler();
9007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mSwipeDirection = swipeDirection;
9107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mVelocityTracker = VelocityTracker.obtain();
92eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        mDensityScale =  context.getResources().getDisplayMetrics().density;
93eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
94469e96e206f8df44b32ce393f8d19f0cae730030Daniel Sandler
95469e96e206f8df44b32ce393f8d19f0cae730030Daniel Sandler        mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press!
96eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
97eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler                android.R.interpolator.fast_out_linear_in);
9819c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek        mFalsingThreshold = context.getResources().getDimensionPixelSize(
9919c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                R.dimen.swipe_helper_falsing_threshold);
10007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
10107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
1024247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler    public void setLongPressListener(LongPressListener listener) {
103f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        mLongPressListener = listener;
104f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    }
105f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
10607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public void setDensityScale(float densityScale) {
10707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mDensityScale = densityScale;
10807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
10907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
11007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public void setPagingTouchSlop(float pagingTouchSlop) {
11107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mPagingTouchSlop = pagingTouchSlop;
11207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
11307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
11407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float getPos(MotionEvent ev) {
11507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeDirection == X ? ev.getX() : ev.getY();
11607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
11707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
1183cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private float getTranslation(View v) {
1193cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
12007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
12107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
12207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float getVelocity(VelocityTracker vt) {
12307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeDirection == X ? vt.getXVelocity() :
12407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                vt.getYVelocity();
12507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
12607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
12707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private ObjectAnimator createTranslationAnimation(View v, float newPos) {
12807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        ObjectAnimator anim = ObjectAnimator.ofFloat(v,
12907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mSwipeDirection == X ? "translationX" : "translationY", newPos);
13007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return anim;
13107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
13207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
13307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float getPerpendicularVelocity(VelocityTracker vt) {
13407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeDirection == X ? vt.getYVelocity() :
13507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                vt.getXVelocity();
13607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
13707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
13807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private void setTranslation(View v, float translate) {
13907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        if (mSwipeDirection == X) {
14007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            v.setTranslationX(translate);
14107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        } else {
14207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            v.setTranslationY(translate);
14307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
14407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
14507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
14607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float getSize(View v) {
14707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeDirection == X ? v.getMeasuredWidth() :
14807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                v.getMeasuredHeight();
14907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
15007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
1515d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    public void setMinSwipeProgress(float minSwipeProgress) {
1525d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        mMinSwipeProgress = minSwipeProgress;
1534eaa983f253d0215d4de777edd8616318610ea22Michael Jurka    }
1544eaa983f253d0215d4de777edd8616318610ea22Michael Jurka
1555d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    public void setMaxSwipeProgress(float maxSwipeProgress) {
1565d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        mMaxSwipeProgress = maxSwipeProgress;
157de61fd7822ea15fb691405c1aae472caa58e83baAdrian Roos    }
158de61fd7822ea15fb691405c1aae472caa58e83baAdrian Roos
1595d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    private float getSwipeProgressForOffset(View view) {
1603cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        float viewSize = getSize(view);
1615d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        final float fadeSize = SWIPE_PROGRESS_FADE_END * viewSize;
16207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        float result = 1.0f;
1633cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        float pos = getTranslation(view);
1645d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        if (pos >= viewSize * SWIPE_PROGRESS_FADE_START) {
1655d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos            result = 1.0f - (pos - viewSize * SWIPE_PROGRESS_FADE_START) / fadeSize;
1665d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        } else if (pos < viewSize * (1.0f - SWIPE_PROGRESS_FADE_START)) {
1675d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos            result = 1.0f + (viewSize * SWIPE_PROGRESS_FADE_START + pos) / fadeSize;
16807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
1695d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        return Math.min(Math.max(mMinSwipeProgress, result), mMaxSwipeProgress);
17007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
17107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
1725d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    private void updateSwipeProgressFromOffset(View animView, boolean dismissable) {
1735d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        float swipeProgress = getSwipeProgressForOffset(animView);
1745d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        if (!mCallback.updateSwipeProgress(animView, dismissable, swipeProgress)) {
1755d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos            if (FADE_OUT_DURING_SWIPE && dismissable) {
1765d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                float alpha = swipeProgress;
1775d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                if (alpha != 0f && alpha != 1f) {
1785d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                    animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
1795d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                } else {
1805d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                    animView.setLayerType(View.LAYER_TYPE_NONE, null);
1815d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                }
1825d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                animView.setAlpha(getSwipeProgressForOffset(animView));
183499293f096ef3182ef39e42cc06284501022b5cfMichael Jurka            }
18467b03701b633c293fd960435cd97fc0835e44568Michael Jurka        }
18567b03701b633c293fd960435cd97fc0835e44568Michael Jurka        invalidateGlobalRegion(animView);
18667b03701b633c293fd960435cd97fc0835e44568Michael Jurka    }
18767b03701b633c293fd960435cd97fc0835e44568Michael Jurka
188a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    // invalidate the view's own bounds all the way up the view hierarchy
189a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    public static void invalidateGlobalRegion(View view) {
190a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler        invalidateGlobalRegion(
191a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler            view,
192a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler            new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
193a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    }
194a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler
195a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    // invalidate a rectangle relative to the view's coordinate system all the way up the view
196a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    // hierarchy
197a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    public static void invalidateGlobalRegion(View view, RectF childBounds) {
19896f4818ef41141649337d4dee09f837594e93d09Daniel Sandler        //childBounds.offset(view.getTranslationX(), view.getTranslationY());
19907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        if (DEBUG_INVALIDATE)
20007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            Log.v(TAG, "-------------");
20107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        while (view.getParent() != null && view.getParent() instanceof View) {
20207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            view = (View) view.getParent();
20307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            view.getMatrix().mapRect(childBounds);
20407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            view.invalidate((int) Math.floor(childBounds.left),
20507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            (int) Math.floor(childBounds.top),
20607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            (int) Math.ceil(childBounds.right),
20707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            (int) Math.ceil(childBounds.bottom));
20807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            if (DEBUG_INVALIDATE) {
20907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
21007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        + "," + (int) Math.floor(childBounds.top)
21107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        + "," + (int) Math.ceil(childBounds.right)
21207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        + "," + (int) Math.ceil(childBounds.bottom));
21307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            }
21407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
21507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
21607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
217469e96e206f8df44b32ce393f8d19f0cae730030Daniel Sandler    public void removeLongPressCallback() {
218f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        if (mWatchLongPress != null) {
219f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler            mHandler.removeCallbacks(mWatchLongPress);
220491d3a9bfab844bf8587545bb1cdab76d2cd4b96Daniel Sandler            mWatchLongPress = null;
221f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        }
222f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    }
223f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
2244247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler    public boolean onInterceptTouchEvent(final MotionEvent ev) {
22507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        final int action = ev.getAction();
22607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
22707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        switch (action) {
22807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_DOWN:
22919c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                mTouchAboveFalsingThreshold = false;
23007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mDragging = false;
231f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                mLongPressSent = false;
23207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mCurrView = mCallback.getChildAtPosition(ev);
23307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mVelocityTracker.clear();
23421ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                if (mCurrView != null) {
23521ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                    mCurrAnimView = mCallback.getChildContentView(mCurrView);
23621ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                    mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
23721ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                    mVelocityTracker.addMovement(ev);
23821ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                    mInitialTouchPos = getPos(ev);
239f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
240f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                    if (mLongPressListener != null) {
241f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                        if (mWatchLongPress == null) {
242f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                            mWatchLongPress = new Runnable() {
243f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                @Override
244f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                public void run() {
245f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                    if (mCurrView != null && !mLongPressSent) {
246f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                        mLongPressSent = true;
2474247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler                                        mCurrView.sendAccessibilityEvent(
2484247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler                                                AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
2494247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler                                        mCurrView.getLocationOnScreen(mTmpPos);
2504247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler                                        final int x = (int) ev.getRawX() - mTmpPos[0];
2514247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler                                        final int y = (int) ev.getRawY() - mTmpPos[1];
2524247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler                                        mLongPressListener.onLongPress(mCurrView, x, y);
253f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                    }
254f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                }
255f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                            };
256f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                        }
257469e96e206f8df44b32ce393f8d19f0cae730030Daniel Sandler                        mHandler.postDelayed(mWatchLongPress, mLongPressTimeout);
258f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                    }
259f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
26021ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                }
26107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                break;
262f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
26307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_MOVE:
264f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                if (mCurrView != null && !mLongPressSent) {
26507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    mVelocityTracker.addMovement(ev);
26607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float pos = getPos(ev);
26707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float delta = pos - mInitialTouchPos;
26807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    if (Math.abs(delta) > mPagingTouchSlop) {
26907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        mCallback.onBeginDrag(mCurrView);
27007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        mDragging = true;
2713cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                        mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView);
272f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
273f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                        removeLongPressCallback();
27407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    }
27507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                }
276f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
27707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                break;
278f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
27907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_UP:
28068ebcdf3fd8b98fe35ec3e0b2e91fd254fcd807fJeff Brown            case MotionEvent.ACTION_CANCEL:
2814247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler                final boolean captured = (mDragging || mLongPressSent);
28207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mDragging = false;
28307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mCurrView = null;
2843cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                mCurrAnimView = null;
285f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                mLongPressSent = false;
286491d3a9bfab844bf8587545bb1cdab76d2cd4b96Daniel Sandler                removeLongPressCallback();
2874247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler                if (captured) return true;
28807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                break;
28907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
2904247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler        return mDragging || mLongPressSent;
29107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
29207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
2932f2022afa1eb85018368398bd150e9575fc099c9Chet Haase    /**
2942f2022afa1eb85018368398bd150e9575fc099c9Chet Haase     * @param view The view to be dismissed
2952f2022afa1eb85018368398bd150e9575fc099c9Chet Haase     * @param velocity The desired pixels/second speed at which the view should move
2962f2022afa1eb85018368398bd150e9575fc099c9Chet Haase     */
2973cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void dismissChild(final View view, float velocity) {
298eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        dismissChild(view, velocity, null, 0, false, 0);
299eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler    }
300eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler
301eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler    /**
302eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler     * @param view The view to be dismissed
303eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler     * @param velocity The desired pixels/second speed at which the view should move
304eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler     * @param endAction The action to perform at the end
305eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler     * @param delay The delay after which we should start
306eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler     * @param useAccelerateInterpolator Should an accelerating Interpolator be used
307eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler     * @param fixedDuration If not 0, this exact duration will be taken
308eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler     */
309eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler    public void dismissChild(final View view, float velocity, final Runnable endAction,
310eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler            long delay, boolean useAccelerateInterpolator, long fixedDuration) {
3113cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        final View animView = mCallback.getChildContentView(view);
3123cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
31307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        float newPos;
3141d59af45f699f11ee559c38698369fd6d159e87aSelim Cinek        boolean isLayoutRtl = view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
315c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka
316c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka        if (velocity < 0
317c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka                || (velocity == 0 && getTranslation(animView) < 0)
318c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka                // if we use the Menu to dismiss an item in landscape, animate up
3191d59af45f699f11ee559c38698369fd6d159e87aSelim Cinek                || (velocity == 0 && getTranslation(animView) == 0 && mSwipeDirection == Y)
3201d59af45f699f11ee559c38698369fd6d159e87aSelim Cinek                // if the language is rtl we prefer swiping to the left
3211d59af45f699f11ee559c38698369fd6d159e87aSelim Cinek                || (velocity == 0 && getTranslation(animView) == 0 && isLayoutRtl)) {
32207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            newPos = -getSize(animView);
32307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        } else {
32407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            newPos = getSize(animView);
32507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
326eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        long duration;
327eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        if (fixedDuration == 0) {
328eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler            duration = MAX_ESCAPE_ANIMATION_DURATION;
329eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler            if (velocity != 0) {
330eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler                duration = Math.min(duration,
331eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler                        (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
332eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler                                .abs(velocity))
333eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler                );
334eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler            } else {
335eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler                duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
336eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler            }
3370e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka        } else {
338eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler            duration = fixedDuration;
33907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
3400e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka
3412f2022afa1eb85018368398bd150e9575fc099c9Chet Haase        animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
34207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        ObjectAnimator anim = createTranslationAnimation(animView, newPos);
343eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        if (useAccelerateInterpolator) {
344eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler            anim.setInterpolator(mFastOutLinearInInterpolator);
345eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        } else {
346eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler            anim.setInterpolator(sLinearInterpolator);
347eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        }
34807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.setDuration(duration);
349eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        if (delay > 0) {
350eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler            anim.setStartDelay(delay);
351eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        }
3522f2022afa1eb85018368398bd150e9575fc099c9Chet Haase        anim.addListener(new AnimatorListenerAdapter() {
35307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            public void onAnimationEnd(Animator animation) {
3543cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                mCallback.onChildDismissed(view);
355eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler                if (endAction != null) {
356eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler                    endAction.run();
357eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler                }
3582f2022afa1eb85018368398bd150e9575fc099c9Chet Haase                animView.setLayerType(View.LAYER_TYPE_NONE, null);
35907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            }
36007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        });
36107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.addUpdateListener(new AnimatorUpdateListener() {
36207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            public void onAnimationUpdate(ValueAnimator animation) {
3635d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
36407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            }
36507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        });
36607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.start();
36707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
36807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
3693cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void snapChild(final View view, float velocity) {
3703cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        final View animView = mCallback.getChildContentView(view);
3713cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(animView);
37207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        ObjectAnimator anim = createTranslationAnimation(animView, 0);
37307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        int duration = SNAP_ANIM_LEN;
37407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.setDuration(duration);
37507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.addUpdateListener(new AnimatorUpdateListener() {
37607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            public void onAnimationUpdate(ValueAnimator animation) {
3775d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
37867b03701b633c293fd960435cd97fc0835e44568Michael Jurka            }
37967b03701b633c293fd960435cd97fc0835e44568Michael Jurka        });
38067b03701b633c293fd960435cd97fc0835e44568Michael Jurka        anim.addListener(new AnimatorListenerAdapter() {
38167b03701b633c293fd960435cd97fc0835e44568Michael Jurka            public void onAnimationEnd(Animator animator) {
3825d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
383eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek                mCallback.onChildSnappedBack(animView);
38407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            }
38507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        });
38607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.start();
38707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
38807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
38907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public boolean onTouchEvent(MotionEvent ev) {
390f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        if (mLongPressSent) {
391f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler            return true;
392f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        }
393f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
39407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        if (!mDragging) {
39528f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi            if (mCallback.getChildAtPosition(ev) != null) {
39628f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi
39728f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi                // We are dragging directly over a card, make sure that we also catch the gesture
39828f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi                // even if nobody else wants the touch event.
39928f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi                onInterceptTouchEvent(ev);
40028f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi                return true;
40128f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi            } else {
40228f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi
40328f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi                // We are not doing anything, make sure the long press callback
40428f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi                // is not still ticking like a bomb waiting to go off.
40528f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi                removeLongPressCallback();
40628f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi                return false;
40728f0e5932944d9abc4b6879b1d05523e9341c385Jorim Jaggi            }
40807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
40907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
41007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mVelocityTracker.addMovement(ev);
41107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        final int action = ev.getAction();
41207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        switch (action) {
41307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_OUTSIDE:
41407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_MOVE:
41507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                if (mCurrView != null) {
41607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float delta = getPos(ev) - mInitialTouchPos;
41719c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                    float absDelta = Math.abs(delta);
41834cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek                    if (absDelta >= getFalsingThreshold()) {
41919c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                        mTouchAboveFalsingThreshold = true;
42019c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                    }
42107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    // don't let items that can't be dismissed be dragged more than
42207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    // maxScrollDistance
42307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
4243cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                        float size = getSize(mCurrAnimView);
42507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        float maxScrollDistance = 0.15f * size;
42619c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                        if (absDelta >= size) {
42707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
42807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        } else {
42907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
43007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        }
43107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    }
4323cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                    setTranslation(mCurrAnimView, delta);
43367b03701b633c293fd960435cd97fc0835e44568Michael Jurka
4345d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos                    updateSwipeProgressFromOffset(mCurrAnimView, mCanCurrViewBeDimissed);
43507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                }
43607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                break;
43707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_UP:
43807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_CANCEL:
43907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                if (mCurrView != null) {
4400761e4cd95b6968dd4b1659a766ef504d13f6d50Daniel Sandler                    float maxVelocity = MAX_DISMISS_VELOCITY * mDensityScale;
44107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, maxVelocity);
44207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale;
44307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float velocity = getVelocity(mVelocityTracker);
44407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
44507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
44607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    // Decide whether to dismiss the current view
44707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
4483cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                            Math.abs(getTranslation(mCurrAnimView)) > 0.4 * getSize(mCurrAnimView);
44907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
45007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
4513cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                            (velocity > 0) == (getTranslation(mCurrAnimView) > 0);
45219c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                    boolean falsingDetected = mCallback.isAntiFalsingNeeded()
45319c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                            && !mTouchAboveFalsingThreshold;
45407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
45519c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                    boolean dismissChild = mCallback.canChildBeDismissed(mCurrView)
456aea80f40d8dc55b7de5b3d0efe78f63eeb7c2745Jorim Jaggi                            && !falsingDetected && (childSwipedFastEnough || childSwipedFarEnough)
457aea80f40d8dc55b7de5b3d0efe78f63eeb7c2745Jorim Jaggi                            && ev.getActionMasked() == MotionEvent.ACTION_UP;
45807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
45907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    if (dismissChild) {
46007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        // flingadingy
46107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f);
46207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    } else {
46307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        // snappity
464622a97646d316ca753c577752ac9010415e9a472Peter Ng                        mCallback.onDragCancelled(mCurrView);
46507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        snapChild(mCurrView, velocity);
46607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    }
46707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                }
46807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                break;
46907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
47007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return true;
47107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
47207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
47334cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek    private int getFalsingThreshold() {
47434cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek        float factor = mCallback.getFalsingThresholdFactor();
47534cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek        return (int) (mFalsingThreshold * factor);
47634cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek    }
47734cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek
47807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public interface Callback {
47907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        View getChildAtPosition(MotionEvent ev);
48007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
48107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        View getChildContentView(View v);
48207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
48307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        boolean canChildBeDismissed(View v);
48407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
48519c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek        boolean isAntiFalsingNeeded();
48619c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek
48707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        void onBeginDrag(View v);
48807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
48907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        void onChildDismissed(View v);
490622a97646d316ca753c577752ac9010415e9a472Peter Ng
491622a97646d316ca753c577752ac9010415e9a472Peter Ng        void onDragCancelled(View v);
492eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek
493eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek        void onChildSnappedBack(View animView);
4945d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos
4955d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        /**
4965d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos         * Updates the swipe progress on a child.
4975d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos         *
4985d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos         * @return if true, prevents the default alpha fading.
4995d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos         */
5005d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress);
50134cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek
50234cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek        /**
50334cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek         * @return The factor the falsing threshold should be multiplied with
50434cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek         */
50534cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek        float getFalsingThresholdFactor();
50607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
5074247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler
5084247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler    /**
5094247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler     * Equivalent to View.OnLongClickListener with coordinates
5104247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler     */
5114247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler    public interface LongPressListener {
5124247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler        /**
5134247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler         * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
5144247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler         * @return whether the longpress was handled
5154247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler         */
5164247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler        boolean onLongPress(View v, int x, int y);
5174247a5c16237705c470b4dd7378a657c5f7b6d51Dan Sandler    }
51807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka}
519