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.Animator.AnimatorListener;
2307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.ValueAnimator;
2407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.ValueAnimator.AnimatorUpdateListener;
2507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.graphics.RectF;
26f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandlerimport android.os.Handler;
2707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.util.Log;
28f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandlerimport android.view.accessibility.AccessibilityEvent;
2907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.animation.LinearInterpolator;
3007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.MotionEvent;
3107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.VelocityTracker;
3207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.View;
33f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandlerimport android.view.ViewConfiguration;
3407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
356a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerpublic class SwipeHelper implements Gefingerpoken {
3607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    static final String TAG = "com.android.systemui.SwipeHelper";
3796f4818ef41141649337d4dee09f837594e93d09Daniel Sandler    private static final boolean DEBUG = false;
3807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private static final boolean DEBUG_INVALIDATE = false;
3907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
403cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private static final boolean CONSTRAIN_SWIPE = true;
413cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private static final boolean FADE_OUT_DURING_SWIPE = true;
423cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
4307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
4407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public static final int X = 0;
4507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public static final int Y = 1;
4607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
472f2022afa1eb85018368398bd150e9575fc099c9Chet Haase    private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
482f2022afa1eb85018368398bd150e9575fc099c9Chet Haase
4907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
500e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka    private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
510e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka    private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
520e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka    private int MAX_DISMISS_VELOCITY = 2000; // dp/sec
530e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
5407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
553cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public static float ALPHA_FADE_START = 0f; // fraction of thumbnail width
5607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                                                 // where fade starts
5707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    static final float ALPHA_FADE_END = 0.5f; // fraction of thumbnail width
5807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                                              // beyond which alpha->0
594eaa983f253d0215d4de777edd8616318610ea22Michael Jurka    private float mMinAlpha = 0f;
6007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
6107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float mPagingTouchSlop;
6207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private Callback mCallback;
63f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    private Handler mHandler;
6407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private int mSwipeDirection;
6507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private VelocityTracker mVelocityTracker;
6607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
6707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float mInitialTouchPos;
6807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private boolean mDragging;
6907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private View mCurrView;
703cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private View mCurrAnimView;
713cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private boolean mCanCurrViewBeDimissed;
7207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float mDensityScale;
7307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
74f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    private boolean mLongPressSent;
75f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    private View.OnLongClickListener mLongPressListener;
76f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    private Runnable mWatchLongPress;
77469e96e206f8df44b32ce393f8d19f0cae730030Daniel Sandler    private long mLongPressTimeout;
78f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
7907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public SwipeHelper(int swipeDirection, Callback callback, float densityScale,
8007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            float pagingTouchSlop) {
8107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mCallback = callback;
82f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        mHandler = new Handler();
8307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mSwipeDirection = swipeDirection;
8407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mVelocityTracker = VelocityTracker.obtain();
8507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mDensityScale = densityScale;
8607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mPagingTouchSlop = pagingTouchSlop;
87469e96e206f8df44b32ce393f8d19f0cae730030Daniel Sandler
88469e96e206f8df44b32ce393f8d19f0cae730030Daniel Sandler        mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press!
8907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
9007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
91f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    public void setLongPressListener(View.OnLongClickListener listener) {
92f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        mLongPressListener = listener;
93f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    }
94f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
9507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public void setDensityScale(float densityScale) {
9607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mDensityScale = densityScale;
9707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
9807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
9907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public void setPagingTouchSlop(float pagingTouchSlop) {
10007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mPagingTouchSlop = pagingTouchSlop;
10107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
10207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
10307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float getPos(MotionEvent ev) {
10407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeDirection == X ? ev.getX() : ev.getY();
10507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
10607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
1073cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private float getTranslation(View v) {
1083cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
10907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
11007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
11107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float getVelocity(VelocityTracker vt) {
11207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeDirection == X ? vt.getXVelocity() :
11307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                vt.getYVelocity();
11407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
11507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
11607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private ObjectAnimator createTranslationAnimation(View v, float newPos) {
11707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        ObjectAnimator anim = ObjectAnimator.ofFloat(v,
11807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mSwipeDirection == X ? "translationX" : "translationY", newPos);
11907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return anim;
12007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
12107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
12207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float getPerpendicularVelocity(VelocityTracker vt) {
12307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeDirection == X ? vt.getYVelocity() :
12407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                vt.getXVelocity();
12507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
12607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
12707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private void setTranslation(View v, float translate) {
12807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        if (mSwipeDirection == X) {
12907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            v.setTranslationX(translate);
13007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        } else {
13107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            v.setTranslationY(translate);
13207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
13307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
13407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
13507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private float getSize(View v) {
13607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeDirection == X ? v.getMeasuredWidth() :
13707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                v.getMeasuredHeight();
13807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
13907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
1404eaa983f253d0215d4de777edd8616318610ea22Michael Jurka    public void setMinAlpha(float minAlpha) {
1414eaa983f253d0215d4de777edd8616318610ea22Michael Jurka        mMinAlpha = minAlpha;
1424eaa983f253d0215d4de777edd8616318610ea22Michael Jurka    }
1434eaa983f253d0215d4de777edd8616318610ea22Michael Jurka
1443cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private float getAlphaForOffset(View view) {
1453cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        float viewSize = getSize(view);
1463cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        final float fadeSize = ALPHA_FADE_END * viewSize;
14707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        float result = 1.0f;
1483cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        float pos = getTranslation(view);
1493cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        if (pos >= viewSize * ALPHA_FADE_START) {
1503cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            result = 1.0f - (pos - viewSize * ALPHA_FADE_START) / fadeSize;
1513cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) {
1523cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
15307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
1544eaa983f253d0215d4de777edd8616318610ea22Michael Jurka        return Math.max(mMinAlpha, result);
15507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
15607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
157a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    // invalidate the view's own bounds all the way up the view hierarchy
158a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    public static void invalidateGlobalRegion(View view) {
159a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler        invalidateGlobalRegion(
160a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler            view,
161a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler            new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
162a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    }
163a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler
164a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    // invalidate a rectangle relative to the view's coordinate system all the way up the view
165a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    // hierarchy
166a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler    public static void invalidateGlobalRegion(View view, RectF childBounds) {
16796f4818ef41141649337d4dee09f837594e93d09Daniel Sandler        //childBounds.offset(view.getTranslationX(), view.getTranslationY());
16807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        if (DEBUG_INVALIDATE)
16907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            Log.v(TAG, "-------------");
17007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        while (view.getParent() != null && view.getParent() instanceof View) {
17107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            view = (View) view.getParent();
17207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            view.getMatrix().mapRect(childBounds);
17307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            view.invalidate((int) Math.floor(childBounds.left),
17407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            (int) Math.floor(childBounds.top),
17507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            (int) Math.ceil(childBounds.right),
17607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            (int) Math.ceil(childBounds.bottom));
17707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            if (DEBUG_INVALIDATE) {
17807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
17907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        + "," + (int) Math.floor(childBounds.top)
18007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        + "," + (int) Math.ceil(childBounds.right)
18107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        + "," + (int) Math.ceil(childBounds.bottom));
18207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            }
18307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
18407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
18507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
186469e96e206f8df44b32ce393f8d19f0cae730030Daniel Sandler    public void removeLongPressCallback() {
187f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        if (mWatchLongPress != null) {
188f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler            mHandler.removeCallbacks(mWatchLongPress);
189491d3a9bfab844bf8587545bb1cdab76d2cd4b96Daniel Sandler            mWatchLongPress = null;
190f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        }
191f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler    }
192f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
19307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public boolean onInterceptTouchEvent(MotionEvent ev) {
19407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        final int action = ev.getAction();
19507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
19607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        switch (action) {
19707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_DOWN:
19807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mDragging = false;
199f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                mLongPressSent = false;
20007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mCurrView = mCallback.getChildAtPosition(ev);
20107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mVelocityTracker.clear();
20221ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                if (mCurrView != null) {
20321ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                    mCurrAnimView = mCallback.getChildContentView(mCurrView);
20421ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                    mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
20521ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                    mVelocityTracker.addMovement(ev);
20621ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                    mInitialTouchPos = getPos(ev);
207f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
208f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                    if (mLongPressListener != null) {
209f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                        if (mWatchLongPress == null) {
210f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                            mWatchLongPress = new Runnable() {
211f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                @Override
212f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                public void run() {
213f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                    if (mCurrView != null && !mLongPressSent) {
214f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                        mLongPressSent = true;
215f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                        mCurrView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
216f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                        mLongPressListener.onLongClick(mCurrView);
217f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                    }
218f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                                }
219f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                            };
220f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                        }
221469e96e206f8df44b32ce393f8d19f0cae730030Daniel Sandler                        mHandler.postDelayed(mWatchLongPress, mLongPressTimeout);
222f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                    }
223f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
22421ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka                }
22507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                break;
226f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
22707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_MOVE:
228f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                if (mCurrView != null && !mLongPressSent) {
22907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    mVelocityTracker.addMovement(ev);
23007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float pos = getPos(ev);
23107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float delta = pos - mInitialTouchPos;
23207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    if (Math.abs(delta) > mPagingTouchSlop) {
23307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        mCallback.onBeginDrag(mCurrView);
23407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        mDragging = true;
2353cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                        mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView);
236f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
237f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                        removeLongPressCallback();
23807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    }
23907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                }
240f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
24107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                break;
242f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
24307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_UP:
24468ebcdf3fd8b98fe35ec3e0b2e91fd254fcd807fJeff Brown            case MotionEvent.ACTION_CANCEL:
24507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mDragging = false;
24607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                mCurrView = null;
2473cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                mCurrAnimView = null;
248f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler                mLongPressSent = false;
249491d3a9bfab844bf8587545bb1cdab76d2cd4b96Daniel Sandler                removeLongPressCallback();
25007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                break;
25107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
25207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mDragging;
25307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
25407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
2552f2022afa1eb85018368398bd150e9575fc099c9Chet Haase    /**
2562f2022afa1eb85018368398bd150e9575fc099c9Chet Haase     * @param view The view to be dismissed
2572f2022afa1eb85018368398bd150e9575fc099c9Chet Haase     * @param velocity The desired pixels/second speed at which the view should move
2582f2022afa1eb85018368398bd150e9575fc099c9Chet Haase     */
2593cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void dismissChild(final View view, float velocity) {
2603cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        final View animView = mCallback.getChildContentView(view);
2613cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
26207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        float newPos;
263c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka
264c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka        if (velocity < 0
265c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka                || (velocity == 0 && getTranslation(animView) < 0)
266c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka                // if we use the Menu to dismiss an item in landscape, animate up
267c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka                || (velocity == 0 && getTranslation(animView) == 0 && mSwipeDirection == Y)) {
26807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            newPos = -getSize(animView);
26907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        } else {
27007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            newPos = getSize(animView);
27107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
27207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        int duration = MAX_ESCAPE_ANIMATION_DURATION;
27307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        if (velocity != 0) {
27407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            duration = Math.min(duration,
2753cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                                (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
27607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                                        .abs(velocity)));
2770e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka        } else {
2780e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka            duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
27907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
2800e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka
2812f2022afa1eb85018368398bd150e9575fc099c9Chet Haase        animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
28207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        ObjectAnimator anim = createTranslationAnimation(animView, newPos);
2832f2022afa1eb85018368398bd150e9575fc099c9Chet Haase        anim.setInterpolator(sLinearInterpolator);
28407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.setDuration(duration);
2852f2022afa1eb85018368398bd150e9575fc099c9Chet Haase        anim.addListener(new AnimatorListenerAdapter() {
28607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            public void onAnimationEnd(Animator animation) {
2873cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                mCallback.onChildDismissed(view);
2882f2022afa1eb85018368398bd150e9575fc099c9Chet Haase                animView.setLayerType(View.LAYER_TYPE_NONE, null);
28907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            }
29007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        });
29107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.addUpdateListener(new AnimatorUpdateListener() {
29207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            public void onAnimationUpdate(ValueAnimator animation) {
2933cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
2943cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                    animView.setAlpha(getAlphaForOffset(animView));
29507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                }
29607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                invalidateGlobalRegion(animView);
29707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            }
29807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        });
29907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.start();
30007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
30107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
3023cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void snapChild(final View view, float velocity) {
3033cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        final View animView = mCallback.getChildContentView(view);
3043cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(animView);
30507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        ObjectAnimator anim = createTranslationAnimation(animView, 0);
30607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        int duration = SNAP_ANIM_LEN;
30707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.setDuration(duration);
30807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.addUpdateListener(new AnimatorUpdateListener() {
30907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            public void onAnimationUpdate(ValueAnimator animation) {
3103cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
3113cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                    animView.setAlpha(getAlphaForOffset(animView));
31207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                }
31307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                invalidateGlobalRegion(animView);
31407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            }
31507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        });
31607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        anim.start();
31707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
31807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
31907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public boolean onTouchEvent(MotionEvent ev) {
320f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        if (mLongPressSent) {
321f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler            return true;
322f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler        }
323f7a1956b06faeb6025fdea331f81d66edda58b3cDaniel Sandler
32407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        if (!mDragging) {
3257f3b379e995651a6ff76d02dddca87b3acdc157eDianne Hackborn            // We are not doing anything, make sure the long press callback
3267f3b379e995651a6ff76d02dddca87b3acdc157eDianne Hackborn            // is not still ticking like a bomb waiting to go off.
3277f3b379e995651a6ff76d02dddca87b3acdc157eDianne Hackborn            removeLongPressCallback();
32807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            return false;
32907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
33007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
33107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mVelocityTracker.addMovement(ev);
33207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        final int action = ev.getAction();
33307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        switch (action) {
33407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_OUTSIDE:
33507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_MOVE:
33607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                if (mCurrView != null) {
33707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float delta = getPos(ev) - mInitialTouchPos;
33807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    // don't let items that can't be dismissed be dragged more than
33907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    // maxScrollDistance
34007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
3413cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                        float size = getSize(mCurrAnimView);
34207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        float maxScrollDistance = 0.15f * size;
34307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        if (Math.abs(delta) >= size) {
34407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
34507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        } else {
34607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
34707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        }
34807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    }
3493cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                    setTranslation(mCurrAnimView, delta);
3503cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                    if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) {
3513cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                        mCurrAnimView.setAlpha(getAlphaForOffset(mCurrAnimView));
35207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    }
35307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    invalidateGlobalRegion(mCurrView);
35407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                }
35507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                break;
35607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_UP:
35707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            case MotionEvent.ACTION_CANCEL:
35807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                if (mCurrView != null) {
3590761e4cd95b6968dd4b1659a766ef504d13f6d50Daniel Sandler                    float maxVelocity = MAX_DISMISS_VELOCITY * mDensityScale;
36007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, maxVelocity);
36107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale;
36207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float velocity = getVelocity(mVelocityTracker);
36307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
36407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
36507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    // Decide whether to dismiss the current view
36607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
3673cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                            Math.abs(getTranslation(mCurrAnimView)) > 0.4 * getSize(mCurrAnimView);
36807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
36907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
3703cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                            (velocity > 0) == (getTranslation(mCurrAnimView) > 0);
37107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
37207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    boolean dismissChild = mCallback.canChildBeDismissed(mCurrView) &&
37307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                            (childSwipedFastEnough || childSwipedFarEnough);
37407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
37507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    if (dismissChild) {
37607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        // flingadingy
37707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f);
37807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    } else {
37907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        // snappity
380622a97646d316ca753c577752ac9010415e9a472Peter Ng                        mCallback.onDragCancelled(mCurrView);
38107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                        snapChild(mCurrView, velocity);
38207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                    }
38307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                }
38407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                break;
38507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        }
38607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return true;
38707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
38807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
38907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public interface Callback {
39007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        View getChildAtPosition(MotionEvent ev);
39107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
39207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        View getChildContentView(View v);
39307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
39407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        boolean canChildBeDismissed(View v);
39507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
39607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        void onBeginDrag(View v);
39707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
39807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        void onChildDismissed(View v);
399622a97646d316ca753c577752ac9010415e9a472Peter Ng
400622a97646d316ca753c577752ac9010415e9a472Peter Ng        void onDragCancelled(View v);
40107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
40207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka}
403