SwipeDismissLayout.java revision df4ee5c8ac0830b23451ea466d48487f8b2205a0
1ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown/* 2ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Copyright (C) 2014 The Android Open Source Project 3ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 4ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Licensed under the Apache License, Version 2.0 (the "License"); 5ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * you may not use this file except in compliance with the License. 6ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * You may obtain a copy of the License at 7ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 8ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * http://www.apache.org/licenses/LICENSE-2.0 9ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 10ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Unless required by applicable law or agreed to in writing, software 11ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * distributed under the License is distributed on an "AS IS" BASIS, 12ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * See the License for the specific language governing permissions and 14ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * limitations under the License. 15ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 16ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 17ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownpackage com.android.internal.widget; 18ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 19ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.animation.TimeInterpolator; 20ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.content.Context; 21ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.util.AttributeSet; 22ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.util.Log; 23ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.MotionEvent; 24ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.VelocityTracker; 25ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.View; 26ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.ViewConfiguration; 27ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.ViewGroup; 28ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.animation.AccelerateInterpolator; 29ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.animation.DecelerateInterpolator; 30ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.widget.FrameLayout; 31ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 32ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown/** 33ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Special layout that finishes its activity when swiped away. 34ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 35ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownpublic class SwipeDismissLayout extends FrameLayout { 36ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private static final String TAG = "SwipeDismissLayout"; 37ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 38ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private static final float TRANSLATION_MIN_ALPHA = 0.5f; 39ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 40ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public interface OnDismissedListener { 41ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onDismissed(SwipeDismissLayout layout); 42ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 43ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 44ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public interface OnSwipeProgressChangedListener { 45ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 46ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Called when the layout has been swiped and the position of the window should change. 47ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 48ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param progress A number in [-1, 1] representing how far to the left 49ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * or right the window has been swiped. Negative values are swipes 50ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * left, and positives are right. 51ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param translate A number in [-w, w], where w is the width of the 52ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * layout. This is equivalent to progress * layout.getWidth(). 53ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 54ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onSwipeProgressChanged(SwipeDismissLayout layout, float progress, float translate); 55ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 56ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onSwipeCancelled(SwipeDismissLayout layout); 57ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 58ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 59ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // Cached ViewConfiguration and system-wide constant values 60ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mSlop; 61ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mMinFlingVelocity; 62ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mMaxFlingVelocity; 63ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private long mAnimationTime; 64ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private TimeInterpolator mCancelInterpolator; 65ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private TimeInterpolator mDismissInterpolator; 66ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 67ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // Transient properties 68ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mActiveTouchId; 69ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mDownX; 70ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mDownY; 71ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mSwiping; 72ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mDismissed; 73ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mDiscardIntercept; 74ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private VelocityTracker mVelocityTracker; 75ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mTranslationX; 76ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 77ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private OnDismissedListener mDismissedListener; 78ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private OnSwipeProgressChangedListener mProgressListener; 79ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 80ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context) { 81ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context); 82ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 83ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 84ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 85ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context, AttributeSet attrs) { 86ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context, attrs); 87ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 88ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 89ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 90ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context, AttributeSet attrs, int defStyle) { 91ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context, attrs, defStyle); 92ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 93ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 94ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 95ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void init(Context context) { 96ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown ViewConfiguration vc = ViewConfiguration.get(getContext()); 97ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mSlop = vc.getScaledTouchSlop(); 98ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16; 99ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); 100ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mAnimationTime = getContext().getResources().getInteger( 101ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown android.R.integer.config_shortAnimTime); 102ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mCancelInterpolator = new DecelerateInterpolator(1.5f); 103ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissInterpolator = new AccelerateInterpolator(1.5f); 104ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 105ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 106ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public void setOnDismissedListener(OnDismissedListener listener) { 107ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissedListener = listener; 108ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 109ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 110ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public void setOnSwipeProgressChangedListener(OnSwipeProgressChangedListener listener) { 111ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener = listener; 112ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 113ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 114ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown @Override 115ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public boolean onInterceptTouchEvent(MotionEvent ev) { 116ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // offset because the view is translated during swipe 117ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown ev.offsetLocation(mTranslationX, 0); 118ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 119ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown switch (ev.getActionMasked()) { 120ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_DOWN: 121ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 122ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownX = ev.getRawX(); 123ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownY = ev.getRawY(); 124ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mActiveTouchId = ev.getPointerId(0); 125ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker = VelocityTracker.obtain(); 126ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.addMovement(ev); 127ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 128ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 129df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh case MotionEvent.ACTION_POINTER_DOWN: 130df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int actionIndex = ev.getActionIndex(); 131df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mActiveTouchId = ev.getPointerId(actionIndex); 132df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 133df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh case MotionEvent.ACTION_POINTER_UP: 134df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh actionIndex = ev.getActionIndex(); 135df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int pointerId = ev.getPointerId(actionIndex); 136df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (pointerId == mActiveTouchId) { 137df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // This was our active pointer going up. Choose a new active pointer. 138df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int newActionIndex = actionIndex == 0 ? 1 : 0; 139df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mActiveTouchId = ev.getPointerId(newActionIndex); 140df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 141df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 142df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh 143ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_CANCEL: 144ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_UP: 145ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 146ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 147ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 148ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_MOVE: 149ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker == null || mDiscardIntercept) { 150ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 151ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 152ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 153ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown int pointerIndex = ev.findPointerIndex(mActiveTouchId); 154df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (pointerIndex == -1) { 155df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh Log.e(TAG, "Invalid pointer index: ignoring."); 156df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mDiscardIntercept = true; 157df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 158df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 159ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float dx = ev.getRawX() - mDownX; 160ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float x = ev.getX(pointerIndex); 161ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float y = ev.getY(pointerIndex); 162ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (dx != 0 && canScroll(this, false, dx, x, y)) { 163ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDiscardIntercept = true; 164ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 165ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 166ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateSwiping(ev); 167ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 168ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 169ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 170ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return !mDiscardIntercept && mSwiping; 171ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 172ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 173ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown @Override 174ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public boolean onTouchEvent(MotionEvent ev) { 175ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker == null) { 176ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return super.onTouchEvent(ev); 177ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 178ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown switch (ev.getActionMasked()) { 179ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_UP: 180ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateDismiss(ev); 181ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mDismissed) { 182ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown dismiss(); 183ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } else if (mSwiping) { 184ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown cancel(); 185ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 186ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 187ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 188ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 189ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_CANCEL: 190ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown cancel(); 191ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 192ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 193ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 194ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_MOVE: 195ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.addMovement(ev); 196ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateSwiping(ev); 197ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateDismiss(ev); 198ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mSwiping) { 199ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown setProgress(ev.getRawX() - mDownX); 200ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 201ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 202ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 203ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return true; 204ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 205ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 206ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void setProgress(float deltaX) { 207ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mTranslationX = deltaX; 208ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mProgressListener != null) { 209ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener.onSwipeProgressChanged(this, deltaX / getWidth(), deltaX); 210ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 211ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 212ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 213ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void dismiss() { 214ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mDismissedListener != null) { 215ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissedListener.onDismissed(this); 216ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 217ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 218ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 219ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown protected void cancel() { 220ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mProgressListener != null) { 221ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener.onSwipeCancelled(this); 222ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 223ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 224ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 225ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 226ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Resets internal members when canceling. 227ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 228ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void resetMembers() { 229ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker != null) { 230ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.recycle(); 231ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 232ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker = null; 233ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mTranslationX = 0; 234ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownX = 0; 235ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownY = 0; 236ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mSwiping = false; 237ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissed = false; 238ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDiscardIntercept = false; 239ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 240ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 241ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void updateSwiping(MotionEvent ev) { 242ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (!mSwiping) { 243ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float deltaX = ev.getRawX() - mDownX; 244ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float deltaY = ev.getRawY() - mDownY; 245ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2; 246ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 247ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 248ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 249ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void updateDismiss(MotionEvent ev) { 250df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh float deltaX = ev.getRawX() - mDownX; 251ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (!mDismissed) { 252ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.addMovement(ev); 253ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.computeCurrentVelocity(1000); 254ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 255ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float velocityX = mVelocityTracker.getXVelocity(); 256ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float absVelocityX = Math.abs(velocityX); 257ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float absVelocityY = Math.abs(mVelocityTracker.getYVelocity()); 258ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 259ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (deltaX > getWidth() / 2) { 260ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissed = true; 261ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } else if (absVelocityX >= mMinFlingVelocity 262ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown && absVelocityX <= mMaxFlingVelocity 263ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown && absVelocityY < absVelocityX / 2 264ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown && velocityX > 0 265ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown && deltaX > 0) { 266ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissed = true; 267ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 268ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 269df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // Check if the user tried to undo this. 270df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (mDismissed && mSwiping) { 271df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // Check if the user's finger is actually back 272df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (deltaX < getWidth() / 2) { 273df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mDismissed = false; 274df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 275df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 276ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 277ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 278ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 279ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Tests scrollability within child views of v in the direction of dx. 280ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 281ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param v View to test for horizontal scrollability 282ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param checkV Whether the view v passed should itself be checked for scrollability (true), 283ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * or just its children (false). 284ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param dx Delta scrolled in pixels. Only the sign of this is used. 285ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param x X coordinate of the active touch point 286ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param y Y coordinate of the active touch point 287ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @return true if child views of v can be scrolled by delta of dx. 288ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 289ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown protected boolean canScroll(View v, boolean checkV, float dx, float x, float y) { 290ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (v instanceof ViewGroup) { 291ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final ViewGroup group = (ViewGroup) v; 292ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int scrollX = v.getScrollX(); 293ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int scrollY = v.getScrollY(); 294ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int count = group.getChildCount(); 295ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown for (int i = count - 1; i >= 0; i--) { 296ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final View child = group.getChildAt(i); 297ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && 298ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && 299ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown canScroll(child, true, dx, x + scrollX - child.getLeft(), 300ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown y + scrollY - child.getTop())) { 301ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return true; 302ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 303ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 304ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 305ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 306ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return checkV && v.canScrollHorizontally((int) -dx); 307ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 308ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown} 309