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; 2607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.util.Log; 2707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.animation.LinearInterpolator; 2807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.MotionEvent; 2907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.VelocityTracker; 3007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.View; 3107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 3207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkapublic class SwipeHelper { 3307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka static final String TAG = "com.android.systemui.SwipeHelper"; 3496f4818ef41141649337d4dee09f837594e93d09Daniel Sandler private static final boolean DEBUG = false; 3507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private static final boolean DEBUG_INVALIDATE = false; 3607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private static final boolean SLOW_ANIMATIONS = false; // DEBUG; 373cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka private static final boolean CONSTRAIN_SWIPE = true; 383cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka private static final boolean FADE_OUT_DURING_SWIPE = true; 393cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true; 4007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 4107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public static final int X = 0; 4207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public static final int Y = 1; 4307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 442f2022afa1eb85018368398bd150e9575fc099c9Chet Haase private static LinearInterpolator sLinearInterpolator = new LinearInterpolator(); 452f2022afa1eb85018368398bd150e9575fc099c9Chet Haase 4607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec 470e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms 480e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms 490e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka private int MAX_DISMISS_VELOCITY = 2000; // dp/sec 500e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms 5107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 523cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka public static float ALPHA_FADE_START = 0f; // fraction of thumbnail width 5307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // where fade starts 5407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka static final float ALPHA_FADE_END = 0.5f; // fraction of thumbnail width 5507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // beyond which alpha->0 5607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 5707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float mPagingTouchSlop; 5807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private Callback mCallback; 5907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private int mSwipeDirection; 6007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private VelocityTracker mVelocityTracker; 6107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 6207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float mInitialTouchPos; 6307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private boolean mDragging; 6407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private View mCurrView; 653cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka private View mCurrAnimView; 663cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka private boolean mCanCurrViewBeDimissed; 6707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float mDensityScale; 6807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 6907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public SwipeHelper(int swipeDirection, Callback callback, float densityScale, 7007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float pagingTouchSlop) { 7107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCallback = callback; 7207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeDirection = swipeDirection; 7307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker = VelocityTracker.obtain(); 7407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mDensityScale = densityScale; 7507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mPagingTouchSlop = pagingTouchSlop; 7607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 7707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 7807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void setDensityScale(float densityScale) { 7907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mDensityScale = densityScale; 8007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 8107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 8207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void setPagingTouchSlop(float pagingTouchSlop) { 8307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mPagingTouchSlop = pagingTouchSlop; 8407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 8507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 8607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getPos(MotionEvent ev) { 8707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeDirection == X ? ev.getX() : ev.getY(); 8807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 8907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 903cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka private float getTranslation(View v) { 913cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY(); 9207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 9307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 9407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getVelocity(VelocityTracker vt) { 9507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeDirection == X ? vt.getXVelocity() : 9607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka vt.getYVelocity(); 9707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 9807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 9907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private ObjectAnimator createTranslationAnimation(View v, float newPos) { 10007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka ObjectAnimator anim = ObjectAnimator.ofFloat(v, 10107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeDirection == X ? "translationX" : "translationY", newPos); 10207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return anim; 10307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 10407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 10507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getPerpendicularVelocity(VelocityTracker vt) { 10607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeDirection == X ? vt.getYVelocity() : 10707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka vt.getXVelocity(); 10807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 10907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 11007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private void setTranslation(View v, float translate) { 11107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (mSwipeDirection == X) { 11207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka v.setTranslationX(translate); 11307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } else { 11407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka v.setTranslationY(translate); 11507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 11607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 11707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 11807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getSize(View v) { 11907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeDirection == X ? v.getMeasuredWidth() : 12007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka v.getMeasuredHeight(); 12107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 12207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 1233cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka private float getAlphaForOffset(View view) { 1243cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka float viewSize = getSize(view); 1253cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka final float fadeSize = ALPHA_FADE_END * viewSize; 12607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float result = 1.0f; 1273cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka float pos = getTranslation(view); 1283cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (pos >= viewSize * ALPHA_FADE_START) { 1293cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka result = 1.0f - (pos - viewSize * ALPHA_FADE_START) / fadeSize; 1303cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) { 1313cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize; 13207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 1330e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka // Make .03 alpha the minimum so you always see the item a bit-- slightly below 1340e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka // .03, the item disappears entirely (as if alpha = 0) and that discontinuity looks 1350e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka // a bit jarring 1360e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka return Math.max(0.03f, result); 13707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 13807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 139a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler // invalidate the view's own bounds all the way up the view hierarchy 140a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler public static void invalidateGlobalRegion(View view) { 141a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler invalidateGlobalRegion( 142a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler view, 143a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom())); 144a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler } 145a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler 146a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler // invalidate a rectangle relative to the view's coordinate system all the way up the view 147a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler // hierarchy 148a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler public static void invalidateGlobalRegion(View view, RectF childBounds) { 14996f4818ef41141649337d4dee09f837594e93d09Daniel Sandler //childBounds.offset(view.getTranslationX(), view.getTranslationY()); 15007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (DEBUG_INVALIDATE) 15107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka Log.v(TAG, "-------------"); 15207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka while (view.getParent() != null && view.getParent() instanceof View) { 15307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka view = (View) view.getParent(); 15407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka view.getMatrix().mapRect(childBounds); 15507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka view.invalidate((int) Math.floor(childBounds.left), 15607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (int) Math.floor(childBounds.top), 15707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (int) Math.ceil(childBounds.right), 15807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (int) Math.ceil(childBounds.bottom)); 15907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (DEBUG_INVALIDATE) { 16007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left) 16107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka + "," + (int) Math.floor(childBounds.top) 16207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka + "," + (int) Math.ceil(childBounds.right) 16307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka + "," + (int) Math.ceil(childBounds.bottom)); 16407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 16507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 16607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 16707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 16807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public boolean onInterceptTouchEvent(MotionEvent ev) { 16907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka final int action = ev.getAction(); 17007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 17107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka switch (action) { 17207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_DOWN: 17307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mDragging = false; 17407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCurrView = mCallback.getChildAtPosition(ev); 17507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker.clear(); 17621ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka if (mCurrView != null) { 17721ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka mCurrAnimView = mCallback.getChildContentView(mCurrView); 17821ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView); 17921ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka mVelocityTracker.addMovement(ev); 18021ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka mInitialTouchPos = getPos(ev); 18121ce2d8caeda3c9eb762a2129d37c384de718941Michael Jurka } 18207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka break; 18307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_MOVE: 18407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (mCurrView != null) { 18507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker.addMovement(ev); 18607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float pos = getPos(ev); 18707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float delta = pos - mInitialTouchPos; 18807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (Math.abs(delta) > mPagingTouchSlop) { 18907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCallback.onBeginDrag(mCurrView); 19007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mDragging = true; 1913cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView); 19207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 19307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 19407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka break; 19507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_UP: 19668ebcdf3fd8b98fe35ec3e0b2e91fd254fcd807fJeff Brown case MotionEvent.ACTION_CANCEL: 19707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mDragging = false; 19807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCurrView = null; 1993cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka mCurrAnimView = null; 20007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka break; 20107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 20207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mDragging; 20307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 20407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 2052f2022afa1eb85018368398bd150e9575fc099c9Chet Haase /** 2062f2022afa1eb85018368398bd150e9575fc099c9Chet Haase * @param view The view to be dismissed 2072f2022afa1eb85018368398bd150e9575fc099c9Chet Haase * @param velocity The desired pixels/second speed at which the view should move 2082f2022afa1eb85018368398bd150e9575fc099c9Chet Haase */ 2093cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka public void dismissChild(final View view, float velocity) { 2103cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka final View animView = mCallback.getChildContentView(view); 2113cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view); 21207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float newPos; 213c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka 214c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka if (velocity < 0 215c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka || (velocity == 0 && getTranslation(animView) < 0) 216c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka // if we use the Menu to dismiss an item in landscape, animate up 217c6461ca5a0892d9b5a47649d49af69165e05b87fMichael Jurka || (velocity == 0 && getTranslation(animView) == 0 && mSwipeDirection == Y)) { 21807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka newPos = -getSize(animView); 21907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } else { 22007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka newPos = getSize(animView); 22107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 22207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka int duration = MAX_ESCAPE_ANIMATION_DURATION; 22307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (velocity != 0) { 22407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka duration = Math.min(duration, 2253cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math 22607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka .abs(velocity))); 2270e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka } else { 2280e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka duration = DEFAULT_ESCAPE_ANIMATION_DURATION; 22907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 2300e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka 2312f2022afa1eb85018368398bd150e9575fc099c9Chet Haase animView.setLayerType(View.LAYER_TYPE_HARDWARE, null); 23207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka ObjectAnimator anim = createTranslationAnimation(animView, newPos); 2332f2022afa1eb85018368398bd150e9575fc099c9Chet Haase anim.setInterpolator(sLinearInterpolator); 23407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.setDuration(duration); 2352f2022afa1eb85018368398bd150e9575fc099c9Chet Haase anim.addListener(new AnimatorListenerAdapter() { 23607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onAnimationEnd(Animator animation) { 2373cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka mCallback.onChildDismissed(view); 2382f2022afa1eb85018368398bd150e9575fc099c9Chet Haase animView.setLayerType(View.LAYER_TYPE_NONE, null); 23907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 24007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka }); 24107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.addUpdateListener(new AnimatorUpdateListener() { 24207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onAnimationUpdate(ValueAnimator animation) { 2433cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) { 2443cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka animView.setAlpha(getAlphaForOffset(animView)); 24507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 24607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka invalidateGlobalRegion(animView); 24707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 24807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka }); 24907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.start(); 25007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 25107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 2523cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka public void snapChild(final View view, float velocity) { 2533cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka final View animView = mCallback.getChildContentView(view); 2543cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(animView); 25507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka ObjectAnimator anim = createTranslationAnimation(animView, 0); 25607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka int duration = SNAP_ANIM_LEN; 25707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.setDuration(duration); 25807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.addUpdateListener(new AnimatorUpdateListener() { 25907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onAnimationUpdate(ValueAnimator animation) { 2603cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) { 2613cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka animView.setAlpha(getAlphaForOffset(animView)); 26207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 26307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka invalidateGlobalRegion(animView); 26407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 26507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka }); 26607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.start(); 26707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 26807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 26907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public boolean onTouchEvent(MotionEvent ev) { 27007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (!mDragging) { 27107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return false; 27207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 27307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 27407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker.addMovement(ev); 27507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka final int action = ev.getAction(); 27607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka switch (action) { 27707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_OUTSIDE: 27807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_MOVE: 27907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (mCurrView != null) { 28007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float delta = getPos(ev) - mInitialTouchPos; 28107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // don't let items that can't be dismissed be dragged more than 28207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // maxScrollDistance 28307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) { 2843cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka float size = getSize(mCurrAnimView); 28507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float maxScrollDistance = 0.15f * size; 28607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (Math.abs(delta) >= size) { 28707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka delta = delta > 0 ? maxScrollDistance : -maxScrollDistance; 28807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } else { 28907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2)); 29007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 29107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 2923cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka setTranslation(mCurrAnimView, delta); 2933cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) { 2943cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka mCurrAnimView.setAlpha(getAlphaForOffset(mCurrAnimView)); 29507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 29607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka invalidateGlobalRegion(mCurrView); 29707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 29807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka break; 29907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_UP: 30007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_CANCEL: 30107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (mCurrView != null) { 3020761e4cd95b6968dd4b1659a766ef504d13f6d50Daniel Sandler float maxVelocity = MAX_DISMISS_VELOCITY * mDensityScale; 30307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, maxVelocity); 30407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale; 30507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float velocity = getVelocity(mVelocityTracker); 30607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker); 30707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 30807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // Decide whether to dismiss the current view 30907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH && 3103cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka Math.abs(getTranslation(mCurrAnimView)) > 0.4 * getSize(mCurrAnimView); 31107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) && 31207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (Math.abs(velocity) > Math.abs(perpendicularVelocity)) && 3133cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka (velocity > 0) == (getTranslation(mCurrAnimView) > 0); 31407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 31507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka boolean dismissChild = mCallback.canChildBeDismissed(mCurrView) && 31607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (childSwipedFastEnough || childSwipedFarEnough); 31707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 31807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (dismissChild) { 31907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // flingadingy 32007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f); 32107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } else { 32207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // snappity 323622a97646d316ca753c577752ac9010415e9a472Peter Ng mCallback.onDragCancelled(mCurrView); 32407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka snapChild(mCurrView, velocity); 32507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 32607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 32707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka break; 32807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 32907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return true; 33007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 33107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 33207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public interface Callback { 33307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka View getChildAtPosition(MotionEvent ev); 33407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 33507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka View getChildContentView(View v); 33607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 33707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka boolean canChildBeDismissed(View v); 33807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 33907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka void onBeginDrag(View v); 34007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 34107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka void onChildDismissed(View v); 342622a97646d316ca753c577752ac9010415e9a472Peter Ng 343622a97646d316ca753c577752ac9010415e9a472Peter Ng void onDragCancelled(View v); 34407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 34507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka} 346