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 193f8dd14451521d728fba548c7655d8fe531ed2efFilip Gruszczynskiimport android.app.Activity; 2006756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynskiimport android.content.BroadcastReceiver; 21ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.content.Context; 2206756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynskiimport android.content.Intent; 2306756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynskiimport android.content.IntentFilter; 2423958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynskiimport android.content.res.TypedArray; 25ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.util.AttributeSet; 26ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.util.Log; 27ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.MotionEvent; 28ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.VelocityTracker; 29ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.View; 30ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.ViewConfiguration; 31ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.ViewGroup; 326eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynskiimport android.view.ViewTreeObserver; 33ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.widget.FrameLayout; 34ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 35ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown/** 36ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Special layout that finishes its activity when swiped away. 37ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 38ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownpublic class SwipeDismissLayout extends FrameLayout { 39ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private static final String TAG = "SwipeDismissLayout"; 40ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 4156e533a5f69e930608f6caf478d4fa5afc7c5eecMindy Pereira private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .33f; 4223958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski private boolean mUseDynamicTranslucency = true; 43ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 44ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public interface OnDismissedListener { 45ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onDismissed(SwipeDismissLayout layout); 46ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 47ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 48ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public interface OnSwipeProgressChangedListener { 49ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 50ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Called when the layout has been swiped and the position of the window should change. 51ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 526c5c48a8b05e7668de551c3bf37aa3f33c7f0920Mark Renouf * @param progress A number in [0, 1] representing how far to the 536c5c48a8b05e7668de551c3bf37aa3f33c7f0920Mark Renouf * right the window has been swiped 546c5c48a8b05e7668de551c3bf37aa3f33c7f0920Mark Renouf * @param translate A number in [0, w], where w is the width of the 55ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * layout. This is equivalent to progress * layout.getWidth(). 56ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 57ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onSwipeProgressChanged(SwipeDismissLayout layout, float progress, float translate); 58ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 59ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onSwipeCancelled(SwipeDismissLayout layout); 60ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 61ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 62ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // Cached ViewConfiguration and system-wide constant values 63ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mSlop; 64ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mMinFlingVelocity; 65ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 66ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // Transient properties 67ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mActiveTouchId; 68ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mDownX; 69ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mDownY; 70ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mSwiping; 71ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mDismissed; 72ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mDiscardIntercept; 73ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private VelocityTracker mVelocityTracker; 74ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mTranslationX; 75ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 76ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private OnDismissedListener mDismissedListener; 77ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private OnSwipeProgressChangedListener mProgressListener; 786eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski private ViewTreeObserver.OnEnterAnimationCompleteListener mOnEnterAnimationCompleteListener = 796eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski new ViewTreeObserver.OnEnterAnimationCompleteListener() { 806eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski @Override 816eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski public void onEnterAnimationComplete() { 826eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski // SwipeDismissLayout assumes that the host Activity is translucent 836eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski // and temporarily disables translucency when it is fully visible. 846eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski // As soon as the user starts swiping, we will re-enable 856eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski // translucency. 8623958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski if (mUseDynamicTranslucency && getContext() instanceof Activity) { 876eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski ((Activity) getContext()).convertFromTranslucent(); 886eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 896eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 906eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski }; 9106756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { 9206756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski @Override 9306756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski public void onReceive(Context context, Intent intent) { 9406756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski if (mDismissed) { 9506756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski dismiss(); 9606756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski } else { 9706756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski cancel(); 9806756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski } 9906756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski resetMembers(); 10006756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski } 10106756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski }; 10206756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski private IntentFilter mScreenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); 103ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 10411b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf private float mLastX; 10511b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf 106ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context) { 107ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context); 108ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 109ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 110ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 111ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context, AttributeSet attrs) { 112ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context, attrs); 113ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 114ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 115ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 116ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context, AttributeSet attrs, int defStyle) { 117ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context, attrs, defStyle); 118ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 119ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 120ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 121ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void init(Context context) { 12255555a3dab1f3b99a3299b90851624e9dc10f3ccMark Renouf ViewConfiguration vc = ViewConfiguration.get(context); 123ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mSlop = vc.getScaledTouchSlop(); 12411b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); 12523958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski TypedArray a = context.getTheme().obtainStyledAttributes( 12623958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski com.android.internal.R.styleable.Theme); 12723958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski mUseDynamicTranslucency = !a.hasValue( 12823958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski com.android.internal.R.styleable.Window_windowIsTranslucent); 12923958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski a.recycle(); 130ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 131ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 132ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public void setOnDismissedListener(OnDismissedListener listener) { 133ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissedListener = listener; 134ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 135ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 136ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public void setOnSwipeProgressChangedListener(OnSwipeProgressChangedListener listener) { 137ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener = listener; 138ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 139ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 140ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown @Override 1416eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski protected void onAttachedToWindow() { 1426eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski super.onAttachedToWindow(); 1436eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski if (getContext() instanceof Activity) { 1446eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski getViewTreeObserver().addOnEnterAnimationCompleteListener( 1456eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski mOnEnterAnimationCompleteListener); 1466eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 14706756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski getContext().registerReceiver(mScreenOffReceiver, mScreenOffFilter); 1486eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 1496eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski 1506eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski @Override 1516eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski protected void onDetachedFromWindow() { 15206756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski getContext().unregisterReceiver(mScreenOffReceiver); 1536eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski if (getContext() instanceof Activity) { 1546eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski getViewTreeObserver().removeOnEnterAnimationCompleteListener( 1556eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski mOnEnterAnimationCompleteListener); 1566eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 15706756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski super.onDetachedFromWindow(); 1586eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 1596eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski 1606eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski @Override 161ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public boolean onInterceptTouchEvent(MotionEvent ev) { 162ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // offset because the view is translated during swipe 163ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown ev.offsetLocation(mTranslationX, 0); 164ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 165ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown switch (ev.getActionMasked()) { 166ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_DOWN: 167ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 168ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownX = ev.getRawX(); 169ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownY = ev.getRawY(); 170ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mActiveTouchId = ev.getPointerId(0); 171ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker = VelocityTracker.obtain(); 172ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.addMovement(ev); 173ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 174ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 175df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh case MotionEvent.ACTION_POINTER_DOWN: 176df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int actionIndex = ev.getActionIndex(); 177df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mActiveTouchId = ev.getPointerId(actionIndex); 178df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 179df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh case MotionEvent.ACTION_POINTER_UP: 180df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh actionIndex = ev.getActionIndex(); 181df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int pointerId = ev.getPointerId(actionIndex); 182df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (pointerId == mActiveTouchId) { 183df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // This was our active pointer going up. Choose a new active pointer. 184df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int newActionIndex = actionIndex == 0 ? 1 : 0; 185df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mActiveTouchId = ev.getPointerId(newActionIndex); 186df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 187df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 188df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh 189ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_CANCEL: 190ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_UP: 191ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 192ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 193ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 194ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_MOVE: 195ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker == null || mDiscardIntercept) { 196ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 197ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 198ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 199ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown int pointerIndex = ev.findPointerIndex(mActiveTouchId); 200df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (pointerIndex == -1) { 201df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh Log.e(TAG, "Invalid pointer index: ignoring."); 202df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mDiscardIntercept = true; 203df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 204df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 205ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float dx = ev.getRawX() - mDownX; 206ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float x = ev.getX(pointerIndex); 207ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float y = ev.getY(pointerIndex); 208ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (dx != 0 && canScroll(this, false, dx, x, y)) { 209ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDiscardIntercept = true; 210ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 211ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 212ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateSwiping(ev); 213ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 214ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 215ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 216ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return !mDiscardIntercept && mSwiping; 217ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 218ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 219ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown @Override 220ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public boolean onTouchEvent(MotionEvent ev) { 221ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker == null) { 222ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return super.onTouchEvent(ev); 223ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 224026e204ee461e101fe251742f6ffb09b1747c804Gus Prevas // offset because the view is translated during swipe 225026e204ee461e101fe251742f6ffb09b1747c804Gus Prevas ev.offsetLocation(mTranslationX, 0); 226ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown switch (ev.getActionMasked()) { 227ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_UP: 228ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateDismiss(ev); 229ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mDismissed) { 230ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown dismiss(); 231ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } else if (mSwiping) { 232ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown cancel(); 233ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 234ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 235ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 236ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 237ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_CANCEL: 238ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown cancel(); 239ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 240ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 241ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 242ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_MOVE: 243ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.addMovement(ev); 24411b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf mLastX = ev.getRawX(); 245ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateSwiping(ev); 246ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mSwiping) { 24723958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski if (mUseDynamicTranslucency && getContext() instanceof Activity) { 248625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski ((Activity) getContext()).convertToTranslucent(null, null); 249625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski } 250ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown setProgress(ev.getRawX() - mDownX); 251ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 252ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 253ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 254ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return true; 255ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 256ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 257ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void setProgress(float deltaX) { 258ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mTranslationX = deltaX; 2596c5c48a8b05e7668de551c3bf37aa3f33c7f0920Mark Renouf if (mProgressListener != null && deltaX >= 0) { 260ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener.onSwipeProgressChanged(this, deltaX / getWidth(), deltaX); 261ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 262ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 263ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 264ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void dismiss() { 265ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mDismissedListener != null) { 266ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissedListener.onDismissed(this); 267ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 268ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 269ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 270ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown protected void cancel() { 27123958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski if (mUseDynamicTranslucency && getContext() instanceof Activity) { 272625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski ((Activity) getContext()).convertFromTranslucent(); 273625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski } 274ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mProgressListener != null) { 275ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener.onSwipeCancelled(this); 276ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 277ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 278ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 279ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 280ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Resets internal members when canceling. 281ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 282ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void resetMembers() { 283ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker != null) { 284ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.recycle(); 285ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 286ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker = null; 287ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mTranslationX = 0; 288ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownX = 0; 289ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownY = 0; 290ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mSwiping = false; 291ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissed = false; 292ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDiscardIntercept = false; 293ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 294ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 295ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void updateSwiping(MotionEvent ev) { 296ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (!mSwiping) { 297ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float deltaX = ev.getRawX() - mDownX; 298ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float deltaY = ev.getRawY() - mDownY; 299072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira if ((deltaX * deltaX) + (deltaY * deltaY) > mSlop * mSlop) { 30055555a3dab1f3b99a3299b90851624e9dc10f3ccMark Renouf mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < Math.abs(deltaX); 301072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira } else { 302072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira mSwiping = false; 303072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira } 304ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 305ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 306ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 307ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void updateDismiss(MotionEvent ev) { 308df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh float deltaX = ev.getRawX() - mDownX; 30955555a3dab1f3b99a3299b90851624e9dc10f3ccMark Renouf mVelocityTracker.addMovement(ev); 31055555a3dab1f3b99a3299b90851624e9dc10f3ccMark Renouf mVelocityTracker.computeCurrentVelocity(1000); 311ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (!mDismissed) { 312ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 313072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira if (deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) && 31411b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf ev.getRawX() >= mLastX) { 315ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissed = true; 316ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 317ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 318df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // Check if the user tried to undo this. 319df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (mDismissed && mSwiping) { 320df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // Check if the user's finger is actually back 32155555a3dab1f3b99a3299b90851624e9dc10f3ccMark Renouf if (deltaX < (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) || 32255555a3dab1f3b99a3299b90851624e9dc10f3ccMark Renouf // or user is flinging back left 32355555a3dab1f3b99a3299b90851624e9dc10f3ccMark Renouf mVelocityTracker.getXVelocity() < -mMinFlingVelocity) { 324df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mDismissed = false; 325df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 326df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 327ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 328ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 329ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 330ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Tests scrollability within child views of v in the direction of dx. 331ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 332ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param v View to test for horizontal scrollability 333ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param checkV Whether the view v passed should itself be checked for scrollability (true), 334ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * or just its children (false). 335ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param dx Delta scrolled in pixels. Only the sign of this is used. 336ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param x X coordinate of the active touch point 337ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param y Y coordinate of the active touch point 338ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @return true if child views of v can be scrolled by delta of dx. 339ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 340ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown protected boolean canScroll(View v, boolean checkV, float dx, float x, float y) { 341ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (v instanceof ViewGroup) { 342ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final ViewGroup group = (ViewGroup) v; 343ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int scrollX = v.getScrollX(); 344ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int scrollY = v.getScrollY(); 345ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int count = group.getChildCount(); 346ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown for (int i = count - 1; i >= 0; i--) { 347ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final View child = group.getChildAt(i); 348ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && 349ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && 350ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown canScroll(child, true, dx, x + scrollX - child.getLeft(), 351ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown y + scrollY - child.getTop())) { 352ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return true; 353ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 354ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 355ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 356ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 357ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return checkV && v.canScrollHorizontally((int) -dx); 358ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 359ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown} 360