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