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 197d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burnsimport android.animation.Animator; 207d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burnsimport android.animation.TimeInterpolator; 217d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burnsimport android.animation.ValueAnimator; 227d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burnsimport android.animation.ValueAnimator.AnimatorUpdateListener; 233f8dd14451521d728fba548c7655d8fe531ed2efFilip Gruszczynskiimport android.app.Activity; 2406756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynskiimport android.content.BroadcastReceiver; 25ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.content.Context; 26d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burnsimport android.content.ContextWrapper; 2706756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynskiimport android.content.Intent; 2806756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynskiimport android.content.IntentFilter; 2923958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynskiimport android.content.res.TypedArray; 30ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.util.AttributeSet; 31ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.util.Log; 32ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.MotionEvent; 33ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.VelocityTracker; 34ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.View; 35ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.ViewConfiguration; 36ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.view.ViewGroup; 377d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burnsimport android.view.animation.DecelerateInterpolator; 38ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownimport android.widget.FrameLayout; 39ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 40ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown/** 41ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Special layout that finishes its activity when swiped away. 42ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 43ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brownpublic class SwipeDismissLayout extends FrameLayout { 44ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private static final String TAG = "SwipeDismissLayout"; 45ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 465758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan private static final float MAX_DIST_THRESHOLD = .33f; 475758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan private static final float MIN_DIST_THRESHOLD = .1f; 48ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 49ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public interface OnDismissedListener { 50ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onDismissed(SwipeDismissLayout layout); 51ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 52ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 53ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public interface OnSwipeProgressChangedListener { 54ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 55ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Called when the layout has been swiped and the position of the window should change. 56ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 577d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns * @param alpha A number in [0, 1] representing what the alpha transparency of the window 587d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns * should be. 596c5c48a8b05e7668de551c3bf37aa3f33c7f0920Mark Renouf * @param translate A number in [0, w], where w is the width of the 60ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * layout. This is equivalent to progress * layout.getWidth(). 61ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 627d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns void onSwipeProgressChanged(SwipeDismissLayout layout, float alpha, float translate); 63ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 64ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown void onSwipeCancelled(SwipeDismissLayout layout); 65ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 66ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 67d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns private boolean mIsWindowNativelyTranslucent; 68d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns 69ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // Cached ViewConfiguration and system-wide constant values 70ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mSlop; 71ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mMinFlingVelocity; 72ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 73ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown // Transient properties 74ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private int mActiveTouchId; 75ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mDownX; 76ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private float mDownY; 775758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan private float mLastX; 78ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mSwiping; 79ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mDismissed; 80ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private boolean mDiscardIntercept; 81ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private VelocityTracker mVelocityTracker; 827d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private boolean mBlockGesture = false; 8339dd370d8e0d04e1a860afc4136ad6bd6d521018Michael Kwan private boolean mActivityTranslucencyConverted = false; 847d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 857d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private final DismissAnimator mDismissAnimator = new DismissAnimator(); 86ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 87ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private OnDismissedListener mDismissedListener; 88ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private OnSwipeProgressChangedListener mProgressListener; 8906756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { 908a148a3b1de69a018867506a42774a47870f6f6cBryce Lee private Runnable mRunnable = new Runnable() { 918a148a3b1de69a018867506a42774a47870f6f6cBryce Lee @Override 928a148a3b1de69a018867506a42774a47870f6f6cBryce Lee public void run() { 938a148a3b1de69a018867506a42774a47870f6f6cBryce Lee if (mDismissed) { 948a148a3b1de69a018867506a42774a47870f6f6cBryce Lee dismiss(); 958a148a3b1de69a018867506a42774a47870f6f6cBryce Lee } else { 968a148a3b1de69a018867506a42774a47870f6f6cBryce Lee cancel(); 978a148a3b1de69a018867506a42774a47870f6f6cBryce Lee } 988a148a3b1de69a018867506a42774a47870f6f6cBryce Lee resetMembers(); 998a148a3b1de69a018867506a42774a47870f6f6cBryce Lee } 1008a148a3b1de69a018867506a42774a47870f6f6cBryce Lee }; 1018a148a3b1de69a018867506a42774a47870f6f6cBryce Lee 10206756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski @Override 10306756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski public void onReceive(Context context, Intent intent) { 1048a148a3b1de69a018867506a42774a47870f6f6cBryce Lee post(mRunnable); 10506756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski } 10606756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski }; 10706756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski private IntentFilter mScreenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); 108ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 10911b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf 110f7964be938338380654aaa41317b28335ed19084Michael Kwan private boolean mDismissable = true; 111f7964be938338380654aaa41317b28335ed19084Michael Kwan 112ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context) { 113ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context); 114ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 115ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 116ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 117ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context, AttributeSet attrs) { 118ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context, attrs); 119ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 120ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 121ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 122ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public SwipeDismissLayout(Context context, AttributeSet attrs, int defStyle) { 123ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown super(context, attrs, defStyle); 124ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown init(context); 125ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 126ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 127ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void init(Context context) { 12855555a3dab1f3b99a3299b90851624e9dc10f3ccMark Renouf ViewConfiguration vc = ViewConfiguration.get(context); 129ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mSlop = vc.getScaledTouchSlop(); 13011b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); 13123958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski TypedArray a = context.getTheme().obtainStyledAttributes( 13223958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski com.android.internal.R.styleable.Theme); 133d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns mIsWindowNativelyTranslucent = a.getBoolean( 134d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns com.android.internal.R.styleable.Window_windowIsTranslucent, false); 13523958c6e2ffd4e76a88bc553fe2874d2f5f3f5e2Filip Gruszczynski a.recycle(); 136ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 137ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 138ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public void setOnDismissedListener(OnDismissedListener listener) { 139ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissedListener = listener; 140ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 141ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 142ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public void setOnSwipeProgressChangedListener(OnSwipeProgressChangedListener listener) { 143ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener = listener; 144ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 145ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 146ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown @Override 1476eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski protected void onAttachedToWindow() { 1486eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski super.onAttachedToWindow(); 14906756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski getContext().registerReceiver(mScreenOffReceiver, mScreenOffFilter); 1506eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 1516eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski 1526eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski @Override 1536eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski protected void onDetachedFromWindow() { 15406756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski getContext().unregisterReceiver(mScreenOffReceiver); 15506756f352d2046246bc147fa1f55d1dfbfcb37f5Filip Gruszczynski super.onDetachedFromWindow(); 1566eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski } 1576eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski 1586eafa902cbc15fa35f8f0dfb5e559673fa67f637Filip Gruszczynski @Override 159ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public boolean onInterceptTouchEvent(MotionEvent ev) { 1607d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns checkGesture((ev)); 1617d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns if (mBlockGesture) { 1627d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns return true; 1637d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 164f7964be938338380654aaa41317b28335ed19084Michael Kwan if (!mDismissable) { 165f7964be938338380654aaa41317b28335ed19084Michael Kwan return super.onInterceptTouchEvent(ev); 166f7964be938338380654aaa41317b28335ed19084Michael Kwan } 167f7964be938338380654aaa41317b28335ed19084Michael Kwan 168390120b925398c754b4f785fc12a8def0d09c09bMichael Kwan // Offset because the view is translated during swipe, match X with raw X. Active touch 169390120b925398c754b4f785fc12a8def0d09c09bMichael Kwan // coordinates are mostly used by the velocity tracker, so offset it to match the raw 170390120b925398c754b4f785fc12a8def0d09c09bMichael Kwan // coordinates which is what is primarily used elsewhere. 171390120b925398c754b4f785fc12a8def0d09c09bMichael Kwan ev.offsetLocation(ev.getRawX() - ev.getX(), 0); 172ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 173ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown switch (ev.getActionMasked()) { 174ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_DOWN: 175ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 176ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownX = ev.getRawX(); 177ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownY = ev.getRawY(); 178ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mActiveTouchId = ev.getPointerId(0); 1795758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan mVelocityTracker = VelocityTracker.obtain("int1"); 180ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.addMovement(ev); 181ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 182ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 183df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh case MotionEvent.ACTION_POINTER_DOWN: 184df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int actionIndex = ev.getActionIndex(); 185df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mActiveTouchId = ev.getPointerId(actionIndex); 186df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 187df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh case MotionEvent.ACTION_POINTER_UP: 188df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh actionIndex = ev.getActionIndex(); 189df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int pointerId = ev.getPointerId(actionIndex); 190df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (pointerId == mActiveTouchId) { 191df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // This was our active pointer going up. Choose a new active pointer. 192df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh int newActionIndex = actionIndex == 0 ? 1 : 0; 193df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mActiveTouchId = ev.getPointerId(newActionIndex); 194df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 195df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 196df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh 197ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_CANCEL: 198ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_UP: 199ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 200ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 201ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 202ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_MOVE: 203ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker == null || mDiscardIntercept) { 204ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 205ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 206ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 207ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown int pointerIndex = ev.findPointerIndex(mActiveTouchId); 208df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (pointerIndex == -1) { 209df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh Log.e(TAG, "Invalid pointer index: ignoring."); 210df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mDiscardIntercept = true; 211df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh break; 212df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 213ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float dx = ev.getRawX() - mDownX; 214ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float x = ev.getX(pointerIndex); 215ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float y = ev.getY(pointerIndex); 216ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (dx != 0 && canScroll(this, false, dx, x, y)) { 217ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDiscardIntercept = true; 218ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 219ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 220ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateSwiping(ev); 221ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 222ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 223ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 224ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return !mDiscardIntercept && mSwiping; 225ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 226ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 227ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown @Override 228ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown public boolean onTouchEvent(MotionEvent ev) { 2297d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns checkGesture((ev)); 2307d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns if (mBlockGesture) { 2317d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns return true; 2327d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 233f7964be938338380654aaa41317b28335ed19084Michael Kwan if (mVelocityTracker == null || !mDismissable) { 234ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return super.onTouchEvent(ev); 235ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 236390120b925398c754b4f785fc12a8def0d09c09bMichael Kwan 237390120b925398c754b4f785fc12a8def0d09c09bMichael Kwan // Offset because the view is translated during swipe, match X with raw X. Active touch 238390120b925398c754b4f785fc12a8def0d09c09bMichael Kwan // coordinates are mostly used by the velocity tracker, so offset it to match the raw 239390120b925398c754b4f785fc12a8def0d09c09bMichael Kwan // coordinates which is what is primarily used elsewhere. 240390120b925398c754b4f785fc12a8def0d09c09bMichael Kwan ev.offsetLocation(ev.getRawX() - ev.getX(), 0); 241390120b925398c754b4f785fc12a8def0d09c09bMichael Kwan 242ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown switch (ev.getActionMasked()) { 243ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_UP: 244ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateDismiss(ev); 245ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mDismissed) { 2467d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mDismissAnimator.animateDismissal(ev.getRawX() - mDownX); 2475758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan } else if (mSwiping 2485758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan // Only trigger animation if we had a MOVE event that would shift the 2495758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan // underlying view, otherwise the animation would be janky. 2505758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan && mLastX != Integer.MIN_VALUE) { 2517d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mDismissAnimator.animateRecovery(ev.getRawX() - mDownX); 252ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 253ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 254ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 255ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 256ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_CANCEL: 257ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown cancel(); 258ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown resetMembers(); 259ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 260ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 261ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown case MotionEvent.ACTION_MOVE: 262ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.addMovement(ev); 26311b1469144d73ad0280ef9d0c2e478d180f17074Mark Renouf mLastX = ev.getRawX(); 264ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown updateSwiping(ev); 265ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mSwiping) { 266ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown setProgress(ev.getRawX() - mDownX); 267ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown break; 268ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 269ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 270ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return true; 271ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 272ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 273ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void setProgress(float deltaX) { 2746c5c48a8b05e7668de551c3bf37aa3f33c7f0920Mark Renouf if (mProgressListener != null && deltaX >= 0) { 2757d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mProgressListener.onSwipeProgressChanged( 2767d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns this, progressToAlpha(deltaX / getWidth()), deltaX); 277ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 278ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 279ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 280ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void dismiss() { 281ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mDismissedListener != null) { 282ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissedListener.onDismissed(this); 283ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 284ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 285ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 286ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown protected void cancel() { 287d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns if (!mIsWindowNativelyTranslucent) { 288d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns Activity activity = findActivity(); 28939dd370d8e0d04e1a860afc4136ad6bd6d521018Michael Kwan if (activity != null && mActivityTranslucencyConverted) { 290d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns activity.convertFromTranslucent(); 29139dd370d8e0d04e1a860afc4136ad6bd6d521018Michael Kwan mActivityTranslucencyConverted = false; 292d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns } 293625ec4849118f061a99558ad558b16020435a88dFilip Gruszczynski } 294ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mProgressListener != null) { 295ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mProgressListener.onSwipeCancelled(this); 296ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 297ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 298ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 299ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 300ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Resets internal members when canceling. 301ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 302ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void resetMembers() { 303ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (mVelocityTracker != null) { 304ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker.recycle(); 305ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 306ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mVelocityTracker = null; 307ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownX = 0; 3085758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan mLastX = Integer.MIN_VALUE; 309ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDownY = 0; 310ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mSwiping = false; 311ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissed = false; 312ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDiscardIntercept = false; 313ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 314ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 315ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void updateSwiping(MotionEvent ev) { 316d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns boolean oldSwiping = mSwiping; 317ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (!mSwiping) { 318ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float deltaX = ev.getRawX() - mDownX; 319ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown float deltaY = ev.getRawY() - mDownY; 320072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira if ((deltaX * deltaX) + (deltaY * deltaY) > mSlop * mSlop) { 32155555a3dab1f3b99a3299b90851624e9dc10f3ccMark Renouf mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < Math.abs(deltaX); 322072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira } else { 323072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira mSwiping = false; 324072c6033fd48900f9f522aad1c984055e38d8380Mindy Pereira } 325ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 326d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns 327d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns if (mSwiping && !oldSwiping) { 328d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns // Swiping has started 329d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns if (!mIsWindowNativelyTranslucent) { 330d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns Activity activity = findActivity(); 331d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns if (activity != null) { 33239dd370d8e0d04e1a860afc4136ad6bd6d521018Michael Kwan mActivityTranslucencyConverted = activity.convertToTranslucent(null, null); 333d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns } 334d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns } 335d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns } 336ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 337ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 338ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown private void updateDismiss(MotionEvent ev) { 339df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh float deltaX = ev.getRawX() - mDownX; 3405758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan // Don't add the motion event as an UP event would clear the velocity tracker 34155555a3dab1f3b99a3299b90851624e9dc10f3ccMark Renouf mVelocityTracker.computeCurrentVelocity(1000); 3425758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan float xVelocity = mVelocityTracker.getXVelocity(); 3435758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan if (mLastX == Integer.MIN_VALUE) { 3445758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan // If there's no changes to mLastX, we have only one point of data, and therefore no 3455758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan // velocity. Estimate velocity from just the up and down event in that case. 3465758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan xVelocity = deltaX / ((ev.getEventTime() - ev.getDownTime()) / 1000); 3475758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan } 348ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (!mDismissed) { 3495758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan // Adjust the distance threshold linearly between the min and max threshold based on the 3505758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan // x-velocity scaled with the the fling threshold speed 3515758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan float distanceThreshold = getWidth() * Math.max( 3525758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan Math.min((MIN_DIST_THRESHOLD - MAX_DIST_THRESHOLD) 3535758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan * xVelocity / mMinFlingVelocity // scale x-velocity with fling velocity 3545758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan + MAX_DIST_THRESHOLD, // offset to start at max threshold 3555758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan MAX_DIST_THRESHOLD), // cap at max threshold 3565758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan MIN_DIST_THRESHOLD); // bottom out at min threshold 3575758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan if ((deltaX > distanceThreshold && ev.getRawX() >= mLastX) 3585758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan || xVelocity >= mMinFlingVelocity) { 359ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown mDismissed = true; 360ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 361ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 362df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh // Check if the user tried to undo this. 363df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh if (mDismissed && mSwiping) { 3648a9b27773b2bd6f84a861bb0d38dcfebb3b8cfa7Michael Kwan // Check if the user's finger is actually flinging back to left 3655758a9a94c7ca1a196b3d1c51b05ec2d937f0b59Michael Kwan if (xVelocity < -mMinFlingVelocity) { 366df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh mDismissed = false; 367df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 368df4ee5c8ac0830b23451ea466d48487f8b2205a0Justin Koh } 369ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 370ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 371ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown /** 372ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * Tests scrollability within child views of v in the direction of dx. 373ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * 374ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param v View to test for horizontal scrollability 375ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param checkV Whether the view v passed should itself be checked for scrollability (true), 376ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * or just its children (false). 377ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param dx Delta scrolled in pixels. Only the sign of this is used. 378ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param x X coordinate of the active touch point 379ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @param y Y coordinate of the active touch point 380ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown * @return true if child views of v can be scrolled by delta of dx. 381ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown */ 382ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown protected boolean canScroll(View v, boolean checkV, float dx, float x, float y) { 383ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (v instanceof ViewGroup) { 384ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final ViewGroup group = (ViewGroup) v; 385ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int scrollX = v.getScrollX(); 386ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int scrollY = v.getScrollY(); 387ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final int count = group.getChildCount(); 388ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown for (int i = count - 1; i >= 0; i--) { 389ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown final View child = group.getChildAt(i); 390ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && 391ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && 392ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown canScroll(child, true, dx, x + scrollX - child.getLeft(), 393ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown y + scrollY - child.getTop())) { 394ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return true; 395ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 396ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 397ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 398ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown 399ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown return checkV && v.canScrollHorizontally((int) -dx); 400ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown } 401f7964be938338380654aaa41317b28335ed19084Michael Kwan 402f7964be938338380654aaa41317b28335ed19084Michael Kwan public void setDismissable(boolean dismissable) { 403f7964be938338380654aaa41317b28335ed19084Michael Kwan if (!dismissable && mDismissable) { 404f7964be938338380654aaa41317b28335ed19084Michael Kwan cancel(); 405f7964be938338380654aaa41317b28335ed19084Michael Kwan resetMembers(); 406f7964be938338380654aaa41317b28335ed19084Michael Kwan } 407f7964be938338380654aaa41317b28335ed19084Michael Kwan 408f7964be938338380654aaa41317b28335ed19084Michael Kwan mDismissable = dismissable; 409f7964be938338380654aaa41317b28335ed19084Michael Kwan } 4107d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4117d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private void checkGesture(MotionEvent ev) { 4127d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { 4137d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mBlockGesture = mDismissAnimator.isAnimating(); 4147d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4157d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4167d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4177d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private float progressToAlpha(float progress) { 4187d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns return 1 - progress * progress * progress; 4197d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4207d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 421d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns private Activity findActivity() { 422d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns Context context = getContext(); 423d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns while (context instanceof ContextWrapper) { 424d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns if (context instanceof Activity) { 425d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns return (Activity) context; 426d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns } 427d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns context = ((ContextWrapper) context).getBaseContext(); 428d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns } 429d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns return null; 430d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns } 431d7a313fb118fb6f5e5eaae6acff253038a85da4bNed Burns 4327d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private class DismissAnimator implements AnimatorUpdateListener, Animator.AnimatorListener { 4337d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private final TimeInterpolator DISMISS_INTERPOLATOR = new DecelerateInterpolator(1.5f); 4347d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private final long DISMISS_DURATION = 250; 4357d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4367d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private final ValueAnimator mDismissAnimator = new ValueAnimator(); 4377d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private boolean mWasCanceled = false; 4387d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private boolean mDismissOnComplete = false; 4397d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4407d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns /* package */ DismissAnimator() { 4417d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mDismissAnimator.addUpdateListener(this); 4427d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mDismissAnimator.addListener(this); 4437d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4447d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4457d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns /* package */ void animateDismissal(float currentTranslation) { 4467d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns animate( 4477d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns currentTranslation / getWidth(), 4487d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 1, 4497d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns DISMISS_DURATION, 4507d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns DISMISS_INTERPOLATOR, 4517d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns true /* dismiss */); 4527d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4537d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4547d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns /* package */ void animateRecovery(float currentTranslation) { 4557d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns animate( 4567d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns currentTranslation / getWidth(), 4577d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 0, 4587d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns DISMISS_DURATION, 4597d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns DISMISS_INTERPOLATOR, 4607d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns false /* don't dismiss */); 4617d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4627d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4637d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns /* package */ boolean isAnimating() { 4647d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns return mDismissAnimator.isStarted(); 4657d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4667d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4677d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns private void animate(float from, float to, long duration, TimeInterpolator interpolator, 4687d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns boolean dismissOnComplete) { 4697d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mDismissAnimator.cancel(); 4707d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mDismissOnComplete = dismissOnComplete; 4717d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mDismissAnimator.setFloatValues(from, to); 4727d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mDismissAnimator.setDuration(duration); 4737d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mDismissAnimator.setInterpolator(interpolator); 4747d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mDismissAnimator.start(); 4757d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4767d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4777d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns @Override 4787d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns public void onAnimationUpdate(ValueAnimator animation) { 4797d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns float value = (Float) animation.getAnimatedValue(); 4807d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns setProgress(value * getWidth()); 4817d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4827d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4837d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns @Override 4847d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns public void onAnimationStart(Animator animation) { 4857d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mWasCanceled = false; 4867d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4877d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4887d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns @Override 4897d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns public void onAnimationCancel(Animator animation) { 4907d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns mWasCanceled = true; 4917d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 4927d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 4937d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns @Override 4947d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns public void onAnimationEnd(Animator animation) { 4957d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns if (!mWasCanceled) { 4967d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns if (mDismissOnComplete) { 4977d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns dismiss(); 4987d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } else { 4997d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns cancel(); 5007d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 5017d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 5027d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 5037d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns 5047d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns @Override 5057d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns public void onAnimationRepeat(Animator animation) { 5067d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 5077d6cb913de9b51dba0bae79e527b7d4fe79eb35dNed Burns } 508ca6234e084a71e0c968cff404620298bcd971fccWill Haldean Brown} 509