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