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; 203f8dd14451521d728fba548c7655d8fe531ed2efFilip Gruszczynskiimport android.app.Activity; 21ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.content.Context; 22ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.util.AttributeSet; 23ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.util.Log; 24ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.MotionEvent; 25ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.VelocityTracker; 26ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.View; 27ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.ViewConfiguration; 28ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.ViewGroup; 296eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynskiimport android.view.ViewTreeObserver; 30ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.animation.AccelerateInterpolator; 31ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.animation.DecelerateInterpolator; 32ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.widget.FrameLayout; 33ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 34ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown/** 35ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Special layout that finishes its activity when swiped away. 36ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 37ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownpublic class SwipeDismissLayout extends FrameLayout { 38ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private static final String TAG = "SwipeDismissLayout"; 39ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 4056e533a5f69e930608f6caf478d4fa5afc7c5eecMindy Pereira private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .33f; 41ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 42ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public interface OnDismissedListener { 43ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onDismissed(SwipeDismissLayout layout); 44ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 45ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 46ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public interface OnSwipeProgressChangedListener { 47ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 48ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Called when the layout has been swiped and the position of the window should change. 49ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 506c5c48a8b05e7668de551c3bf37aa3f33c7f0920Mark Renouf * @param progress A number in [0, 1] representing how far to the 516c5c48a8b05e7668de551c3bf37aa3f33c7f0920Mark Renouf * right the window has been swiped 526c5c48a8b05e7668de551c3bf37aa3f33c7f0920Mark Renouf * @param translate A number in [0, w], where w is the width of the 53ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * layout. This is equivalent to progress * layout.getWidth(). 54ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 55ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onSwipeProgressChanged(SwipeDismissLayout layout, float progress, float translate); 56ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 57ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onSwipeCancelled(SwipeDismissLayout layout); 58ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 59ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 60ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // Cached ViewConfiguration and system-wide constant values 61ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mSlop; 62ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mMinFlingVelocity; 63ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mMaxFlingVelocity; 64ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private long mAnimationTime; 65ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private TimeInterpolator mCancelInterpolator; 66ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private TimeInterpolator mDismissInterpolator; 67ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 68ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // Transient properties 69ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mActiveTouchId; 70ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mDownX; 71ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mDownY; 72ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mSwiping; 73ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mDismissed; 74ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mDiscardIntercept; 75ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private VelocityTracker mVelocityTracker; 76ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mTranslationX; 77ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 78ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private OnDismissedListener mDismissedListener; 79ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private OnSwipeProgressChangedListener mProgressListener; 806eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski private ViewTreeObserver.OnEnterAnimationCompleteListener mOnEnterAnimationCompleteListener = 816eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski new ViewTreeObserver.OnEnterAnimationCompleteListener() { 826eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski @Override 836eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski public void onEnterAnimationComplete() { 846eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski // SwipeDismissLayout assumes that the host Activity is translucent 856eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski // and temporarily disables translucency when it is fully visible. 866eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski // As soon as the user starts swiping, we will re-enable 876eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski // translucency. 886eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski if (getContext() instanceof Activity) { 896eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski ((Activity) getContext()).convertFromTranslucent(); 906eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 916eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 926eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski }; 93ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 9411b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf private float mLastX; 9511b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf 96ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context) { 97ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context); 98ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 99ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 100ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 101ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context, AttributeSet attrs) { 102ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context, attrs); 103ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 104ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 105ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 106ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context, AttributeSet attrs, int defStyle) { 107ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context, attrs, defStyle); 108ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 109ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 110ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 111ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void init(Context context) { 112ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown ViewConfiguration vc = ViewConfiguration.get(getContext()); 113ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mSlop = vc.getScaledTouchSlop(); 11411b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); 115ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); 116ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mAnimationTime = getContext().getResources().getInteger( 117ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown android.R.integer.config_shortAnimTime); 118ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mCancelInterpolator = new DecelerateInterpolator(1.5f); 119ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissInterpolator = new AccelerateInterpolator(1.5f); 120ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 121ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 122ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public void setOnDismissedListener(OnDismissedListener listener) { 123ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissedListener = listener; 124ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 125ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 126ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public void setOnSwipeProgressChangedListener(OnSwipeProgressChangedListener listener) { 127ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener = listener; 128ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 129ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 130ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown @Override 1316eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski protected void onAttachedToWindow() { 1326eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski super.onAttachedToWindow(); 1336eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski if (getContext() instanceof Activity) { 1346eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski getViewTreeObserver().addOnEnterAnimationCompleteListener( 1356eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski mOnEnterAnimationCompleteListener); 1366eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 1376eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 1386eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski 1396eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski @Override 1406eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski protected void onDetachedFromWindow() { 1416eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski super.onDetachedFromWindow(); 1426eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski if (getContext() instanceof Activity) { 1436eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski getViewTreeObserver().removeOnEnterAnimationCompleteListener( 1446eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski mOnEnterAnimationCompleteListener); 1456eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 1466eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 1476eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski 1486eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski @Override 149ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public boolean onInterceptTouchEvent(MotionEvent ev) { 150ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // offset because the view is translated during swipe 151ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown ev.offsetLocation(mTranslationX, 0); 152ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 153ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown switch (ev.getActionMasked()) { 154ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_DOWN: 155ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 156ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownX = ev.getRawX(); 157ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownY = ev.getRawY(); 158ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mActiveTouchId = ev.getPointerId(0); 159ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker = VelocityTracker.obtain(); 160ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.addMovement(ev); 161ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 162ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 163df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh case MotionEvent.ACTION_POINTER_DOWN: 164df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int actionIndex = ev.getActionIndex(); 165df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mActiveTouchId = ev.getPointerId(actionIndex); 166df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 167df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh case MotionEvent.ACTION_POINTER_UP: 168df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh actionIndex = ev.getActionIndex(); 169df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int pointerId = ev.getPointerId(actionIndex); 170df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (pointerId == mActiveTouchId) { 171df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // This was our active pointer going up. Choose a new active pointer. 172df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int newActionIndex = actionIndex == 0 ? 1 : 0; 173df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mActiveTouchId = ev.getPointerId(newActionIndex); 174df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 175df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 176df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh 177ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_CANCEL: 178ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_UP: 179ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 180ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 181ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 182ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_MOVE: 183ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker == null || mDiscardIntercept) { 184ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 185ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 186ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 187ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown int pointerIndex = ev.findPointerIndex(mActiveTouchId); 188df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (pointerIndex == -1) { 189df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh Log.e(TAG, "Invalid pointer index: ignoring."); 190df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mDiscardIntercept = true; 191df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 192df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 193ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float dx = ev.getRawX() - mDownX; 194ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float x = ev.getX(pointerIndex); 195ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float y = ev.getY(pointerIndex); 196ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (dx != 0 && canScroll(this, false, dx, x, y)) { 197ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDiscardIntercept = true; 198ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 199ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 200ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateSwiping(ev); 201ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 202ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 203ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 204ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return !mDiscardIntercept && mSwiping; 205ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 206ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 207ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown @Override 208ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public boolean onTouchEvent(MotionEvent ev) { 209ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker == null) { 210ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return super.onTouchEvent(ev); 211ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 212ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown switch (ev.getActionMasked()) { 213ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_UP: 214ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateDismiss(ev); 215ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mDismissed) { 216ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown dismiss(); 217ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } else if (mSwiping) { 218ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown cancel(); 219ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 220ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 221ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 222ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 223ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_CANCEL: 224ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown cancel(); 225ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 226ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 227ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 228ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_MOVE: 229ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.addMovement(ev); 23011b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf mLastX = ev.getRawX(); 231ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateSwiping(ev); 232ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mSwiping) { 233625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski if (getContext() instanceof Activity) { 234625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski ((Activity) getContext()).convertToTranslucent(null, null); 235625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski } 236ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown setProgress(ev.getRawX() - mDownX); 237ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 238ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 239ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 240ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return true; 241ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 242ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 243ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void setProgress(float deltaX) { 244ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mTranslationX = deltaX; 2456c5c48a8b05e7668de551c3bf37aa3f33c7f0920Mark Renouf if (mProgressListener != null && deltaX >= 0) { 246ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener.onSwipeProgressChanged(this, deltaX / getWidth(), deltaX); 247ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 248ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 249ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 250ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void dismiss() { 251ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mDismissedListener != null) { 252ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissedListener.onDismissed(this); 253ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 254ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 255ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 256ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown protected void cancel() { 257625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski if (getContext() instanceof Activity) { 258625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski ((Activity) getContext()).convertFromTranslucent(); 259625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski } 260ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mProgressListener != null) { 261ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener.onSwipeCancelled(this); 262ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 263ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 264ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 265ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 266ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Resets internal members when canceling. 267ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 268ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void resetMembers() { 269ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker != null) { 270ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.recycle(); 271ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 272ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker = null; 273ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mTranslationX = 0; 274ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownX = 0; 275ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownY = 0; 276ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mSwiping = false; 277ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissed = false; 278ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDiscardIntercept = false; 279ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 280ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 281ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void updateSwiping(MotionEvent ev) { 282ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (!mSwiping) { 283ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float deltaX = ev.getRawX() - mDownX; 284ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float deltaY = ev.getRawY() - mDownY; 285072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira if ((deltaX * deltaX) + (deltaY * deltaY) > mSlop * mSlop) { 286072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2; 287072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira } else { 288072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira mSwiping = false; 289072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira } 290ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 291ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 292ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 293ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void updateDismiss(MotionEvent ev) { 294df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh float deltaX = ev.getRawX() - mDownX; 295ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (!mDismissed) { 296ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.addMovement(ev); 297ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.computeCurrentVelocity(1000); 298ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 299072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira if (deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) && 30011b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf ev.getRawX() >= mLastX) { 301ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissed = true; 302ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 303ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 304df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // Check if the user tried to undo this. 305df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (mDismissed && mSwiping) { 306df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // Check if the user's finger is actually back 307072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira if (deltaX < (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO)) { 308df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mDismissed = false; 309df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 310df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 311ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 312ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 313ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 314ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Tests scrollability within child views of v in the direction of dx. 315ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 316ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param v View to test for horizontal scrollability 317ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param checkV Whether the view v passed should itself be checked for scrollability (true), 318ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * or just its children (false). 319ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param dx Delta scrolled in pixels. Only the sign of this is used. 320ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param x X coordinate of the active touch point 321ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param y Y coordinate of the active touch point 322ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @return true if child views of v can be scrolled by delta of dx. 323ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 324ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown protected boolean canScroll(View v, boolean checkV, float dx, float x, float y) { 325ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (v instanceof ViewGroup) { 326ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final ViewGroup group = (ViewGroup) v; 327ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int scrollX = v.getScrollX(); 328ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int scrollY = v.getScrollY(); 329ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int count = group.getChildCount(); 330ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown for (int i = count - 1; i >= 0; i--) { 331ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final View child = group.getChildAt(i); 332ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && 333ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && 334ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown canScroll(child, true, dx, x + scrollX - child.getLeft(), 335ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown y + scrollY - child.getTop())) { 336ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return true; 337ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 338ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 339ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 340ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 341ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return checkV && v.canScrollHorizontally((int) -dx); 342ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 343ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown} 344