15c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng/* 25c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Copyright (C) 2012 Google Inc. 35c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Licensed to The Android Open Source Project. 45c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * 55c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Licensed under the Apache License, Version 2.0 (the "License"); 65c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * you may not use this file except in compliance with the License. 75c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * You may obtain a copy of the License at 85c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * 95c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * http://www.apache.org/licenses/LICENSE-2.0 105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * 115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Unless required by applicable law or agreed to in writing, software 125c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * distributed under the License is distributed on an "AS IS" BASIS, 135c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 145c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * See the License for the specific language governing permissions and 155c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * limitations under the License. 165c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng */ 175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 185c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengpackage com.android.deskclock.widget.swipeablelistview; 195c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 205c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.animation.Animator; 215c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.animation.AnimatorListenerAdapter; 225c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.animation.ObjectAnimator; 235c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.animation.ValueAnimator; 245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.animation.ValueAnimator.AnimatorUpdateListener; 255c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.content.Context; 265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.content.res.Resources; 275c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.graphics.RectF; 285c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.util.Log; 295c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.MotionEvent; 305c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.VelocityTracker; 315c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.View; 325c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.animation.LinearInterpolator; 335c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 345c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport com.android.deskclock.R; 355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 365c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng/** 375c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Copy of packages/apps/UnifiedEmail - com.android.mail.ui.SwipeHelper with changes. 385c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng */ 395c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengpublic class SwipeHelper { 405c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng static final String TAG = "com.android.systemui.SwipeHelper"; 415c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static final boolean DEBUG_INVALIDATE = false; 425c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static final boolean CONSTRAIN_SWIPE = true; 435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static final boolean FADE_OUT_DURING_SWIPE = true; 445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true; 455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static final boolean LOG_SWIPE_DISMISS_VELOCITY = false; // STOPSHIP - DEBUG ONLY 465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public static final int X = 0; 485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public static final int Y = 1; 495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static LinearInterpolator sLinearInterpolator = new LinearInterpolator(); 515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static int SWIPE_ESCAPE_VELOCITY = -1; 535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static int DEFAULT_ESCAPE_ANIMATION_DURATION; 545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static int MAX_ESCAPE_ANIMATION_DURATION; 555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static int MAX_DISMISS_VELOCITY; 565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static int SNAP_ANIM_LEN; 575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static int DISMISS_ANIMATION_DURATION; 585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static int SWIPE_SCROLL_SLOP; 595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static float MIN_SWIPE; 605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static float MIN_VERT; 615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static float MIN_LOCK; 625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 635c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public static float ALPHA_FADE_START = 0f; // fraction of thumbnail width 645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // where fade starts 655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng static final float ALPHA_FADE_END = 0.7f; // fraction of thumbnail width 665c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // beyond which alpha->0 675c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private static final float FACTOR = 1.2f; 682a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng 692a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng private static final int PROTECTION_PADDING = 50; 702a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng 71aba3c451dccd54617947628045367c65febdee6bChiao Cheng private float mMinAlpha = 0.3f; 725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private float mPagingTouchSlop; 74af70181fffc83d61d949714b4893a37863e63c2eIsaac Katzenelson private final Callback mCallback; 75af70181fffc83d61d949714b4893a37863e63c2eIsaac Katzenelson private final int mSwipeDirection; 76af70181fffc83d61d949714b4893a37863e63c2eIsaac Katzenelson private final VelocityTracker mVelocityTracker; 775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private float mInitialTouchPosX; 795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private boolean mDragging; 805c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private View mCurrView; 815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private View mCurrAnimView; 825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private boolean mCanCurrViewBeDimissed; 835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private float mDensityScale; 845c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private float mLastY; 855c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private float mInitialTouchPosY; 865c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 87aba3c451dccd54617947628045367c65febdee6bChiao Cheng private float mStartAlpha; 882a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng private boolean mProtected = false; 89aba3c451dccd54617947628045367c65febdee6bChiao Cheng 905c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public SwipeHelper(Context context, int swipeDirection, Callback callback, float densityScale, 915c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float pagingTouchSlop) { 925c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCallback = callback; 935c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mSwipeDirection = swipeDirection; 945c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mVelocityTracker = VelocityTracker.obtain(); 955c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mDensityScale = densityScale; 965c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mPagingTouchSlop = pagingTouchSlop; 975c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (SWIPE_ESCAPE_VELOCITY == -1) { 985c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng Resources res = context.getResources(); 995c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng SWIPE_ESCAPE_VELOCITY = res.getInteger(R.integer.swipe_escape_velocity); 1005c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng DEFAULT_ESCAPE_ANIMATION_DURATION = res.getInteger(R.integer.escape_animation_duration); 1015c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng MAX_ESCAPE_ANIMATION_DURATION = res.getInteger(R.integer.max_escape_animation_duration); 1025c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng MAX_DISMISS_VELOCITY = res.getInteger(R.integer.max_dismiss_velocity); 1035c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng SNAP_ANIM_LEN = res.getInteger(R.integer.snap_animation_duration); 1045c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng DISMISS_ANIMATION_DURATION = res.getInteger(R.integer.dismiss_animation_duration); 1055c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng SWIPE_SCROLL_SLOP = res.getInteger(R.integer.swipe_scroll_slop); 1065c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng MIN_SWIPE = res.getDimension(R.dimen.min_swipe); 1075c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng MIN_VERT = res.getDimension(R.dimen.min_vert); 1085c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng MIN_LOCK = res.getDimension(R.dimen.min_lock); 1095c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1125c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void setDensityScale(float densityScale) { 1135c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mDensityScale = densityScale; 1145c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1155c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1165c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void setPagingTouchSlop(float pagingTouchSlop) { 1175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mPagingTouchSlop = pagingTouchSlop; 1185c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1195c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1205c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private float getVelocity(VelocityTracker vt) { 1215c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return mSwipeDirection == X ? vt.getXVelocity() : 1225c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng vt.getYVelocity(); 1235c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1255c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private ObjectAnimator createTranslationAnimation(View v, float newPos) { 1265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng ObjectAnimator anim = ObjectAnimator.ofFloat(v, 1275c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mSwipeDirection == X ? "translationX" : "translationY", newPos); 1285c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return anim; 1295c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1305c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1315c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private ObjectAnimator createDismissAnimation(View v, float newPos, int duration) { 1325c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng ObjectAnimator anim = createTranslationAnimation(v, newPos); 1335c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng anim.setInterpolator(sLinearInterpolator); 1345c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng anim.setDuration(duration); 1355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return anim; 1365c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1375c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1385c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private float getPerpendicularVelocity(VelocityTracker vt) { 1395c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return mSwipeDirection == X ? vt.getYVelocity() : 1405c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng vt.getXVelocity(); 1415c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1425c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private void setTranslation(View v, float translate) { 1445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (mSwipeDirection == X) { 1455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng v.setTranslationX(translate); 1465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } else { 1475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng v.setTranslationY(translate); 1485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private float getSize(View v) { 1525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return mSwipeDirection == X ? v.getMeasuredWidth() : 1535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng v.getMeasuredHeight(); 1545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void setMinAlpha(float minAlpha) { 1575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mMinAlpha = minAlpha; 1585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private float getAlphaForOffset(View view) { 1615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float viewSize = getSize(view); 1625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng final float fadeSize = ALPHA_FADE_END * viewSize; 163aba3c451dccd54617947628045367c65febdee6bChiao Cheng float result = mStartAlpha; 1645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float pos = view.getTranslationX(); 1655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (pos >= viewSize * ALPHA_FADE_START) { 166aba3c451dccd54617947628045367c65febdee6bChiao Cheng result = mStartAlpha - (pos - viewSize * ALPHA_FADE_START) / fadeSize; 167aba3c451dccd54617947628045367c65febdee6bChiao Cheng } else if (pos < viewSize * (mStartAlpha - ALPHA_FADE_START)) { 168aba3c451dccd54617947628045367c65febdee6bChiao Cheng result = mStartAlpha + (viewSize * ALPHA_FADE_START + pos) / fadeSize; 1695c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1705c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return Math.max(mMinAlpha, result); 1715c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // invalidate the view's own bounds all the way up the view hierarchy 1745c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public static void invalidateGlobalRegion(View view) { 1755c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng invalidateGlobalRegion( 1765c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng view, 1775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom())); 1785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 1805c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // invalidate a rectangle relative to the view's coordinate system all the way up the view 1815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // hierarchy 1825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public static void invalidateGlobalRegion(View view, RectF childBounds) { 1835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng //childBounds.offset(view.getTranslationX(), view.getTranslationY()); 1845c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (DEBUG_INVALIDATE) 1855c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng Log.v(TAG, "-------------"); 1865c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng while (view.getParent() != null && view.getParent() instanceof View) { 1875c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng view = (View) view.getParent(); 1885c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng view.getMatrix().mapRect(childBounds); 1895c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng view.invalidate((int) Math.floor(childBounds.left), 1905c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng (int) Math.floor(childBounds.top), 1915c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng (int) Math.ceil(childBounds.right), 1925c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng (int) Math.ceil(childBounds.bottom)); 1935c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (DEBUG_INVALIDATE) { 1945c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left) 1955c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng + "," + (int) Math.floor(childBounds.top) 1965c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng + "," + (int) Math.ceil(childBounds.right) 1975c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng + "," + (int) Math.ceil(childBounds.bottom)); 1985c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 1995c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 2005c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 2015c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 2025c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public boolean onInterceptTouchEvent(MotionEvent ev) { 2035c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng final int action = ev.getAction(); 2045c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng switch (action) { 2055c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng case MotionEvent.ACTION_DOWN: 2065c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mLastY = ev.getY(); 2075c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mDragging = false; 2085c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCurrView = mCallback.getChildAtPosition(ev); 2095c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mVelocityTracker.clear(); 2105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (mCurrView != null) { 2112a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng 2122a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng View button = mCurrView.findViewById(R.id.onoff); 2132a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng 2142a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng // Find raw top and left positions for button. 2152a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng int left = button.getLeft(); 2162a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng int top = button.getTop(); 2172a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng View parent = (View) button.getParent(); 2182a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng while (parent != null) { 2192a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng left += parent.getLeft(); 2202a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng top += parent.getTop(); 2212a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng if (parent.getParent() == parent.getRootView()) { 2222a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng parent = null; 2232a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng } else { 2242a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng parent = (View) parent.getParent(); 2252a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng } 2262a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng } 2272a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng 2282a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng // Add protection. 2292a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng int bottom = top + button.getHeight() + PROTECTION_PADDING; 2302a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng top -= PROTECTION_PADDING; 2312a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng left -= PROTECTION_PADDING; 2322a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng 2332a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng float rawX = ev.getRawX(); 2342a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng float rawY = ev.getRawY(); 2352a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng 2362a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng // Check if we are in the protected no-op area. 2372a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng if (rawX > left && rawY > top && rawY < bottom) { 2382a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng mProtected = true; 2392a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng } else { 2402a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng mProtected = false; 2412a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng } 2422a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng 2435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCurrAnimView = mCallback.getChildContentView(mCurrView); 244aba3c451dccd54617947628045367c65febdee6bChiao Cheng mStartAlpha = mCurrAnimView.getAlpha(); 2455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView); 2465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mVelocityTracker.addMovement(ev); 2475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mInitialTouchPosX = ev.getX(); 2485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mInitialTouchPosY = ev.getY(); 2495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 2505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng break; 2515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng case MotionEvent.ACTION_MOVE: 2525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (mCurrView != null) { 2535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // Check the movement direction. 2545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (mLastY >= 0 && !mDragging) { 2555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float currY = ev.getY(); 2565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float currX = ev.getX(); 2575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float deltaY = Math.abs(currY - mInitialTouchPosY); 2585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float deltaX = Math.abs(currX - mInitialTouchPosX); 2595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (deltaY > SWIPE_SCROLL_SLOP && deltaY > (FACTOR * deltaX)) { 2605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mLastY = ev.getY(); 2615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCallback.onScroll(); 2625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return false; 2635c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 2645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 2655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mVelocityTracker.addMovement(ev); 2665c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float pos = ev.getX(); 2675c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float delta = pos - mInitialTouchPosX; 2685c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (Math.abs(delta) > mPagingTouchSlop) { 2695c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCallback.onBeginDrag(mCallback.getChildContentView(mCurrView)); 2705c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mDragging = true; 2715c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mInitialTouchPosX = ev.getX() - mCurrAnimView.getTranslationX(); 2725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mInitialTouchPosY = ev.getY(); 2735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 2745c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 2755c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mLastY = ev.getY(); 2765c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng break; 2775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng case MotionEvent.ACTION_UP: 2785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng case MotionEvent.ACTION_CANCEL: 2795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mDragging = false; 2805c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCurrView = null; 2815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCurrAnimView = null; 2825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mLastY = -1; 2835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng break; 2845c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 2855c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return mDragging; 2865c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 2875c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 2885c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng /** 2895c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * @param view The view to be dismissed 2905c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * @param velocity The desired pixels/second speed at which the view should 2915c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * move 2925c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng */ 2935c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private void dismissChild(final View view, float velocity) { 2945c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng final View animView = mCallback.getChildContentView(view); 2955c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view); 2965c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float newPos = determinePos(animView, velocity); 2975c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng int duration = determineDuration(animView, newPos, velocity); 2985c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 2995c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng animView.setLayerType(View.LAYER_TYPE_HARDWARE, null); 3005c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng ObjectAnimator anim = createDismissAnimation(animView, newPos, duration); 3015c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng anim.addListener(new AnimatorListenerAdapter() { 3025c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng @Override 3035c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void onAnimationEnd(Animator animation) { 3045c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCallback.onChildDismissed(mCurrView); 3055c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng animView.setLayerType(View.LAYER_TYPE_NONE, null); 3065c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3075c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng }); 3085c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng anim.addUpdateListener(new AnimatorUpdateListener() { 3095c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng @Override 3105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void onAnimationUpdate(ValueAnimator animation) { 3115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) { 3125c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng animView.setAlpha(getAlphaForOffset(animView)); 3135c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3145c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng invalidateGlobalRegion(animView); 3155c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3165c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng }); 3175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng anim.start(); 3185c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3195c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 3205c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private int determineDuration(View animView, float newPos, float velocity) { 3215c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng int duration = MAX_ESCAPE_ANIMATION_DURATION; 3225c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (velocity != 0) { 3235c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng duration = Math 3245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng .min(duration, 3255c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng (int) (Math.abs(newPos - animView.getTranslationX()) * 1000f / Math 3265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng .abs(velocity))); 3275c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } else { 3285c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng duration = DEFAULT_ESCAPE_ANIMATION_DURATION; 3295c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3305c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return duration; 3315c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3325c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 3335c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng private float determinePos(View animView, float velocity) { 3345c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float newPos = 0; 3355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (velocity < 0 || (velocity == 0 && animView.getTranslationX() < 0) 3365c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // if we use the Menu to dismiss an item in landscape, animate up 3375c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng || (velocity == 0 && animView.getTranslationX() == 0 && mSwipeDirection == Y)) { 3385c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng newPos = -getSize(animView); 3395c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } else { 3405c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng newPos = getSize(animView); 3415c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3425c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return newPos; 3435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 3455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void snapChild(final View view, float velocity) { 3465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng final View animView = mCallback.getChildContentView(view); 3475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view); 3485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng ObjectAnimator anim = createTranslationAnimation(animView, 0); 3495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng int duration = SNAP_ANIM_LEN; 3505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng anim.setDuration(duration); 3515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng anim.addUpdateListener(new AnimatorUpdateListener() { 3525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng @Override 3535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void onAnimationUpdate(ValueAnimator animation) { 3545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) { 3555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng animView.setAlpha(getAlphaForOffset(animView)); 3565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng invalidateGlobalRegion(animView); 3585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng }); 3605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng anim.addListener(new Animator.AnimatorListener() { 3615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng @Override 3625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void onAnimationStart(Animator animation) { 3635c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng @Override 3655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void onAnimationEnd(Animator animation) { 366aba3c451dccd54617947628045367c65febdee6bChiao Cheng animView.setAlpha(mStartAlpha); 3675c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCallback.onDragCancelled(mCurrView); 3685c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3695c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng @Override 3705c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void onAnimationCancel(Animator animation) { 3715c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng @Override 3735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public void onAnimationRepeat(Animator animation) { 3745c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3755c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng }); 3765c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng anim.start(); 3775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 3795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public boolean onTouchEvent(MotionEvent ev) { 3802a6b929796cdcac7553c732d94e60d9b47dff859Chiao Cheng if (!mDragging || mProtected) { 3815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return false; 3825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mVelocityTracker.addMovement(ev); 3845c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng final int action = ev.getAction(); 3855c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng switch (action) { 3865c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng case MotionEvent.ACTION_OUTSIDE: 3875c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng case MotionEvent.ACTION_MOVE: 3885c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (mCurrView != null) { 3895c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float deltaX = ev.getX() - mInitialTouchPosX; 3905c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float deltaY = Math.abs(ev.getY() - mInitialTouchPosY); 3915c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // If the user has gone vertical and not gone horizontalish AT 3925c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // LEAST minBeforeLock, switch to scroll. Otherwise, cancel 3935c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // the swipe. 3945c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (!mDragging && deltaY > MIN_VERT && (Math.abs(deltaX)) < MIN_LOCK 3955c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng && deltaY > (FACTOR * Math.abs(deltaX))) { 3965c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCallback.onScroll(); 3975c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return false; 3985c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 3995c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float minDistance = MIN_SWIPE; 4005c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (Math.abs(deltaX) < minDistance) { 4015c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // Don't start the drag until at least X distance has 4025c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // occurred. 4035c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return true; 4045c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4055c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // don't let items that can't be dismissed be dragged more 4065c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // than maxScrollDistance 4075c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) { 4085c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float size = getSize(mCurrAnimView); 4095c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float maxScrollDistance = 0.15f * size; 4105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (Math.abs(deltaX) >= size) { 4115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng deltaX = deltaX > 0 ? maxScrollDistance : -maxScrollDistance; 4125c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } else { 4135c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng deltaX = maxScrollDistance 4145c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * (float) Math.sin((deltaX / size) * (Math.PI / 2)); 4155c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4165c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng setTranslation(mCurrAnimView, deltaX); 4185c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) { 4195c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mCurrAnimView.setAlpha(getAlphaForOffset(mCurrAnimView)); 4205c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4215c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng invalidateGlobalRegion(mCallback.getChildContentView(mCurrView)); 4225c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4235c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng break; 4245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng case MotionEvent.ACTION_UP: 4255c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng case MotionEvent.ACTION_CANCEL: 4265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (mCurrView != null) { 4275c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float maxVelocity = MAX_DISMISS_VELOCITY * mDensityScale; 4285c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, maxVelocity); 4295c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale; 4305c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float velocity = getVelocity(mVelocityTracker); 4315c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker); 4325c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4335c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // Decide whether to dismiss the current view 4345c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // Tweak constants below as required to prevent erroneous 4355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // swipe/dismiss 4365c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float translation = Math.abs(mCurrAnimView.getTranslationX()); 4375c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng float currAnimViewSize = getSize(mCurrAnimView); 4385c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // Long swipe = translation of .4 * width 4395c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH 440aba3c451dccd54617947628045367c65febdee6bChiao Cheng && translation > 0.4 * currAnimViewSize; 4415c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // Fast swipe = > escapeVelocity and translation of .1 * 4425c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng // width 4435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) 4445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng && (Math.abs(velocity) > Math.abs(perpendicularVelocity)) 4455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng && (velocity > 0) == (mCurrAnimView.getTranslationX() > 0) 4465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng && translation > 0.05 * currAnimViewSize; 4475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (LOG_SWIPE_DISMISS_VELOCITY) { 4485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng Log.v(TAG, "Swipe/Dismiss: " + velocity + "/" + escapeVelocity + "/" 4495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng + perpendicularVelocity + ", x: " + translation + "/" 4505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng + currAnimViewSize); 4515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng boolean dismissChild = mCallback.canChildBeDismissed(mCurrView) 4545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng && (childSwipedFastEnough || childSwipedFarEnough); 4555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng if (dismissChild) { 4575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f); 4585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } else { 4595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng snapChild(mCurrView, velocity); 4605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng break; 4635c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng return true; 4655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4665c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4675c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng public interface Callback { 4685c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng View getChildAtPosition(MotionEvent ev); 4695c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4705c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng View getChildContentView(View v); 4715c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng void onScroll(); 4735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4745c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng boolean canChildBeDismissed(View v); 4755c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4765c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng void onBeginDrag(View v); 4775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng void onChildDismissed(View v); 4795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4805c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng void onDragCancelled(View v); 4815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng 4825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng } 4835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng} 484