blob: d17ca4041b31e300596e35e9817b657cbebf5bc1 [file] [log] [blame]
Michael Jurka07d40462011-07-19 10:54:38 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui;
18
19import android.animation.Animator;
Chet Haase2f2022a2011-10-11 06:41:59 -070020import android.animation.AnimatorListenerAdapter;
Michael Jurka07d40462011-07-19 10:54:38 -070021import android.animation.ObjectAnimator;
Michael Jurka07d40462011-07-19 10:54:38 -070022import android.animation.ValueAnimator;
23import android.animation.ValueAnimator.AnimatorUpdateListener;
yoshiki iguchi355692b2018-01-15 11:14:25 +090024import android.annotation.NonNull;
Dan Sandlereceda3d2014-07-21 15:35:01 -040025import android.content.Context;
Anthony Chen7acbb772017-04-07 16:45:25 -070026import android.content.res.Resources;
Michael Jurka07d40462011-07-19 10:54:38 -070027import android.graphics.RectF;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040028import android.os.Handler;
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070029import android.util.ArrayMap;
Michael Jurka07d40462011-07-19 10:54:38 -070030import android.util.Log;
Michael Jurka07d40462011-07-19 10:54:38 -070031import android.view.MotionEvent;
32import android.view.VelocityTracker;
33import android.view.View;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040034import android.view.ViewConfiguration;
John Spurlockde84f0e2013-06-12 12:41:00 -040035import android.view.accessibility.AccessibilityEvent;
Gus Prevas37d67e22018-11-02 14:48:55 -040036
Dave Mankoff468d4f62019-05-08 14:56:29 -040037import com.android.systemui.plugins.FalsingManager;
Mady Mellor4ab28202017-06-06 11:42:50 -070038import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
Mady Mellor28796312016-03-08 14:12:42 -080039import com.android.systemui.statusbar.FlingAnimationUtils;
Gus Prevas37d67e22018-11-02 14:48:55 -040040import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Blazej Magnowski6dc59b42015-09-22 15:14:20 -070041
Daniel Sandler6a858c32012-03-12 14:38:58 -040042public class SwipeHelper implements Gefingerpoken {
Michael Jurka07d40462011-07-19 10:54:38 -070043 static final String TAG = "com.android.systemui.SwipeHelper";
Daniel Sandler96f48182011-08-17 09:50:35 -040044 private static final boolean DEBUG = false;
Michael Jurka07d40462011-07-19 10:54:38 -070045 private static final boolean DEBUG_INVALIDATE = false;
46 private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
Michael Jurka3cd0a592011-08-16 12:40:30 -070047 private static final boolean CONSTRAIN_SWIPE = true;
48 private static final boolean FADE_OUT_DURING_SWIPE = true;
49 private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
Michael Jurka07d40462011-07-19 10:54:38 -070050
51 public static final int X = 0;
52 public static final int Y = 1;
53
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070054 private static final float SWIPE_ESCAPE_VELOCITY = 500f; // dp/sec
55 private static final int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
56 private static final int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
57 private static final int MAX_DISMISS_VELOCITY = 4000; // dp/sec
Michael Jurka0e8063a2011-09-09 15:31:55 -070058 private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
Michael Jurka07d40462011-07-19 10:54:38 -070059
Adrian Roos5d9cc662014-05-28 17:08:13 +020060 static final float SWIPE_PROGRESS_FADE_END = 0.5f; // fraction of thumbnail width
61 // beyond which swipe progress->0
Mady Mellor55744252017-04-10 10:05:17 -070062 public static final float SWIPED_FAR_ENOUGH_SIZE_FRACTION = 0.6f;
63 static final float MAX_SCROLL_SIZE_FRACTION = 0.3f;
64
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040065 protected final Handler mHandler;
66
Adrian Roos5d9cc662014-05-28 17:08:13 +020067 private float mMinSwipeProgress = 0f;
68 private float mMaxSwipeProgress = 1f;
Michael Jurka07d40462011-07-19 10:54:38 -070069
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070070 private final FlingAnimationUtils mFlingAnimationUtils;
Michael Jurka07d40462011-07-19 10:54:38 -070071 private float mPagingTouchSlop;
Philip Quinn47169132020-03-23 19:04:55 -070072 private final float mSlopMultiplier;
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070073 private final Callback mCallback;
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070074 private final int mSwipeDirection;
75 private final VelocityTracker mVelocityTracker;
76 private final FalsingManager mFalsingManager;
Michael Jurka07d40462011-07-19 10:54:38 -070077
78 private float mInitialTouchPos;
Jorim Jaggi9b0a2c92016-01-26 18:34:13 -080079 private float mPerpendicularInitialTouchPos;
Michael Jurka07d40462011-07-19 10:54:38 -070080 private boolean mDragging;
dongwan0605.kim30637e42016-03-02 17:16:47 +090081 private boolean mSnappingChild;
Michael Jurka07d40462011-07-19 10:54:38 -070082 private View mCurrView;
Michael Jurka3cd0a592011-08-16 12:40:30 -070083 private boolean mCanCurrViewBeDimissed;
Michael Jurka07d40462011-07-19 10:54:38 -070084 private float mDensityScale;
Mady Mellor4b80b102016-01-22 08:03:58 -080085 private float mTranslation = 0;
Michael Jurka07d40462011-07-19 10:54:38 -070086
Mady Mellor4ab28202017-06-06 11:42:50 -070087 private boolean mMenuRowIntercepting;
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070088 private final long mLongPressTimeout;
Philip Quinn47169132020-03-23 19:04:55 -070089 private boolean mLongPressSent;
90 private final float[] mDownLocation = new float[2];
91 private final Runnable mPerformLongPress = new Runnable() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -040092
Philip Quinn47169132020-03-23 19:04:55 -070093 private final int[] mViewOffset = new int[2];
94
95 @Override
96 public void run() {
97 if (mCurrView != null && !mLongPressSent) {
98 mLongPressSent = true;
99 if (mCurrView instanceof ExpandableNotificationRow) {
100 mCurrView.getLocationOnScreen(mViewOffset);
101 final int x = (int) mDownLocation[0] - mViewOffset[0];
102 final int y = (int) mDownLocation[1] - mViewOffset[1];
103 mCurrView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
104 ((ExpandableNotificationRow) mCurrView).doLongClickCallback(x, y);
105 }
106 }
107 }
108 };
109
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -0700110 private final int mFalsingThreshold;
Selim Cinek19c8c702014-08-25 22:09:19 +0200111 private boolean mTouchAboveFalsingThreshold;
Winson671e8f92016-01-12 13:16:56 -0800112 private boolean mDisableHwLayers;
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -0700113 private final boolean mFadeDependingOnAmountSwiped;
Dan Sandler4247a5c2014-07-23 15:58:08 -0400114
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -0700115 private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
dongwan0605.kim30637e42016-03-02 17:16:47 +0900116
Dave Mankoffc195ea82019-06-28 16:33:25 -0400117 public SwipeHelper(
118 int swipeDirection, Callback callback, Context context, FalsingManager falsingManager) {
Michael Jurka07d40462011-07-19 10:54:38 -0700119 mCallback = callback;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400120 mHandler = new Handler();
Michael Jurka07d40462011-07-19 10:54:38 -0700121 mSwipeDirection = swipeDirection;
122 mVelocityTracker = VelocityTracker.obtain();
Philip Quinn47169132020-03-23 19:04:55 -0700123 final ViewConfiguration configuration = ViewConfiguration.get(context);
124 mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
125 mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
Daniel Sandler469e96e2012-05-04 15:56:19 -0400126
Anthony Chen7acbb772017-04-07 16:45:25 -0700127 // Extra long-press!
128 mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
129
130 Resources res = context.getResources();
131 mDensityScale = res.getDisplayMetrics().density;
132 mFalsingThreshold = res.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
133 mFadeDependingOnAmountSwiped = res.getBoolean(R.bool.config_fadeDependingOnAmountSwiped);
Dave Mankoffc195ea82019-06-28 16:33:25 -0400134 mFalsingManager = falsingManager;
Dave Mankoff1373fdb2019-12-18 14:04:37 -0500135 mFlingAnimationUtils = new FlingAnimationUtils(res.getDisplayMetrics(),
136 getMaxEscapeAnimDuration() / 1000f);
Michael Jurka07d40462011-07-19 10:54:38 -0700137 }
138
139 public void setDensityScale(float densityScale) {
140 mDensityScale = densityScale;
141 }
142
143 public void setPagingTouchSlop(float pagingTouchSlop) {
144 mPagingTouchSlop = pagingTouchSlop;
145 }
146
Winson671e8f92016-01-12 13:16:56 -0800147 public void setDisableHardwareLayers(boolean disableHwLayers) {
148 mDisableHwLayers = disableHwLayers;
149 }
150
Michael Jurka07d40462011-07-19 10:54:38 -0700151 private float getPos(MotionEvent ev) {
152 return mSwipeDirection == X ? ev.getX() : ev.getY();
153 }
154
Jorim Jaggi9b0a2c92016-01-26 18:34:13 -0800155 private float getPerpendicularPos(MotionEvent ev) {
156 return mSwipeDirection == X ? ev.getY() : ev.getX();
157 }
158
Mady Mellor4b80b102016-01-22 08:03:58 -0800159 protected float getTranslation(View v) {
Michael Jurka3cd0a592011-08-16 12:40:30 -0700160 return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
Michael Jurka07d40462011-07-19 10:54:38 -0700161 }
162
163 private float getVelocity(VelocityTracker vt) {
164 return mSwipeDirection == X ? vt.getXVelocity() :
165 vt.getYVelocity();
166 }
167
Mady Mellor4b80b102016-01-22 08:03:58 -0800168 protected ObjectAnimator createTranslationAnimation(View v, float newPos) {
Michael Jurka07d40462011-07-19 10:54:38 -0700169 ObjectAnimator anim = ObjectAnimator.ofFloat(v,
Winsonc5fd3502016-01-18 15:18:37 -0800170 mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
Michael Jurka07d40462011-07-19 10:54:38 -0700171 return anim;
172 }
173
174 private float getPerpendicularVelocity(VelocityTracker vt) {
175 return mSwipeDirection == X ? vt.getYVelocity() :
176 vt.getXVelocity();
177 }
178
Mady Mellor4b80b102016-01-22 08:03:58 -0800179 protected Animator getViewTranslationAnimator(View v, float target,
180 AnimatorUpdateListener listener) {
181 ObjectAnimator anim = createTranslationAnimation(v, target);
Mady Mellor34958fa2016-02-23 09:52:17 -0800182 if (listener != null) {
183 anim.addUpdateListener(listener);
184 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800185 return anim;
186 }
187
188 protected void setTranslation(View v, float translate) {
189 if (v == null) {
190 return;
191 }
Michael Jurka07d40462011-07-19 10:54:38 -0700192 if (mSwipeDirection == X) {
193 v.setTranslationX(translate);
194 } else {
195 v.setTranslationY(translate);
196 }
197 }
198
Winson671e8f92016-01-12 13:16:56 -0800199 protected float getSize(View v) {
Anthony Chen7acbb772017-04-07 16:45:25 -0700200 return mSwipeDirection == X ? v.getMeasuredWidth() : v.getMeasuredHeight();
Michael Jurka07d40462011-07-19 10:54:38 -0700201 }
202
Adrian Roos5d9cc662014-05-28 17:08:13 +0200203 public void setMinSwipeProgress(float minSwipeProgress) {
204 mMinSwipeProgress = minSwipeProgress;
Michael Jurka4eaa9832012-02-29 15:51:49 -0800205 }
206
Adrian Roos5d9cc662014-05-28 17:08:13 +0200207 public void setMaxSwipeProgress(float maxSwipeProgress) {
208 mMaxSwipeProgress = maxSwipeProgress;
Adrian Roosde61fd72014-05-26 14:59:15 +0200209 }
210
Winsonbde852d2016-04-15 19:06:54 -0700211 private float getSwipeProgressForOffset(View view, float translation) {
Michael Jurka3cd0a592011-08-16 12:40:30 -0700212 float viewSize = getSize(view);
Winsonbde852d2016-04-15 19:06:54 -0700213 float result = Math.abs(translation / viewSize);
Adrian Roos5d9cc662014-05-28 17:08:13 +0200214 return Math.min(Math.max(mMinSwipeProgress, result), mMaxSwipeProgress);
Michael Jurka07d40462011-07-19 10:54:38 -0700215 }
216
Winsonbde852d2016-04-15 19:06:54 -0700217 private float getSwipeAlpha(float progress) {
Anthony Chen7acbb772017-04-07 16:45:25 -0700218 if (mFadeDependingOnAmountSwiped) {
219 // The more progress has been fade, the lower the alpha value so that the view fades.
220 return Math.max(1 - progress, 0);
221 }
222
Winson Chungd8a52f22017-08-10 14:13:37 -0700223 return 1f - Math.max(0, Math.min(1, progress / SWIPE_PROGRESS_FADE_END));
Winsonbde852d2016-04-15 19:06:54 -0700224 }
225
Adrian Roos5d9cc662014-05-28 17:08:13 +0200226 private void updateSwipeProgressFromOffset(View animView, boolean dismissable) {
Winsonbde852d2016-04-15 19:06:54 -0700227 updateSwipeProgressFromOffset(animView, dismissable, getTranslation(animView));
228 }
229
230 private void updateSwipeProgressFromOffset(View animView, boolean dismissable,
231 float translation) {
232 float swipeProgress = getSwipeProgressForOffset(animView, translation);
Adrian Roos5d9cc662014-05-28 17:08:13 +0200233 if (!mCallback.updateSwipeProgress(animView, dismissable, swipeProgress)) {
234 if (FADE_OUT_DURING_SWIPE && dismissable) {
Winson671e8f92016-01-12 13:16:56 -0800235 if (!mDisableHwLayers) {
Anthony Chen7acbb772017-04-07 16:45:25 -0700236 if (swipeProgress != 0f && swipeProgress != 1f) {
Winson671e8f92016-01-12 13:16:56 -0800237 animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
238 } else {
239 animView.setLayerType(View.LAYER_TYPE_NONE, null);
240 }
Adrian Roos5d9cc662014-05-28 17:08:13 +0200241 }
Winsonbde852d2016-04-15 19:06:54 -0700242 animView.setAlpha(getSwipeAlpha(swipeProgress));
Michael Jurka499293f2013-03-06 18:08:45 +0100243 }
Michael Jurka67b03702013-02-15 17:35:48 +0100244 }
245 invalidateGlobalRegion(animView);
246 }
247
Daniel Sandlera375c942011-07-29 00:33:53 -0400248 // invalidate the view's own bounds all the way up the view hierarchy
249 public static void invalidateGlobalRegion(View view) {
250 invalidateGlobalRegion(
251 view,
252 new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
253 }
254
255 // invalidate a rectangle relative to the view's coordinate system all the way up the view
256 // hierarchy
257 public static void invalidateGlobalRegion(View view, RectF childBounds) {
Daniel Sandler96f48182011-08-17 09:50:35 -0400258 //childBounds.offset(view.getTranslationX(), view.getTranslationY());
Michael Jurka07d40462011-07-19 10:54:38 -0700259 if (DEBUG_INVALIDATE)
260 Log.v(TAG, "-------------");
261 while (view.getParent() != null && view.getParent() instanceof View) {
262 view = (View) view.getParent();
263 view.getMatrix().mapRect(childBounds);
264 view.invalidate((int) Math.floor(childBounds.left),
265 (int) Math.floor(childBounds.top),
266 (int) Math.ceil(childBounds.right),
267 (int) Math.ceil(childBounds.bottom));
268 if (DEBUG_INVALIDATE) {
269 Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
270 + "," + (int) Math.floor(childBounds.top)
271 + "," + (int) Math.ceil(childBounds.right)
272 + "," + (int) Math.ceil(childBounds.bottom));
273 }
274 }
275 }
276
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000277 public void cancelLongPress() {
Philip Quinn47169132020-03-23 19:04:55 -0700278 mHandler.removeCallbacks(mPerformLongPress);
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400279 }
280
Mady Mellor43c2cd12016-12-12 21:05:13 -0800281 @Override
Dan Sandler4247a5c2014-07-23 15:58:08 -0400282 public boolean onInterceptTouchEvent(final MotionEvent ev) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700283 if (mCurrView instanceof ExpandableNotificationRow) {
284 NotificationMenuRowPlugin nmr = ((ExpandableNotificationRow) mCurrView).getProvider();
Evan Lairde55c6012019-03-13 12:54:37 -0400285 if (nmr != null) {
286 mMenuRowIntercepting = nmr.onInterceptTouchEvent(mCurrView, ev);
287 }
Mady Mellor4ab28202017-06-06 11:42:50 -0700288 }
Michael Jurka07d40462011-07-19 10:54:38 -0700289 final int action = ev.getAction();
290
291 switch (action) {
292 case MotionEvent.ACTION_DOWN:
Selim Cinek19c8c702014-08-25 22:09:19 +0200293 mTouchAboveFalsingThreshold = false;
Michael Jurka07d40462011-07-19 10:54:38 -0700294 mDragging = false;
dongwan0605.kim30637e42016-03-02 17:16:47 +0900295 mSnappingChild = false;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400296 mLongPressSent = false;
Michael Jurka07d40462011-07-19 10:54:38 -0700297 mVelocityTracker.clear();
Mady Mellor4b80b102016-01-22 08:03:58 -0800298 mCurrView = mCallback.getChildAtPosition(ev);
299
Michael Jurka21ce2d82011-09-02 15:28:06 -0700300 if (mCurrView != null) {
Mady Mellor95d743c2017-01-10 12:05:27 -0800301 onDownUpdate(mCurrView, ev);
Michael Jurka21ce2d82011-09-02 15:28:06 -0700302 mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
303 mVelocityTracker.addMovement(ev);
304 mInitialTouchPos = getPos(ev);
Jorim Jaggi9b0a2c92016-01-26 18:34:13 -0800305 mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
Mady Mellor4b80b102016-01-22 08:03:58 -0800306 mTranslation = getTranslation(mCurrView);
Philip Quinn47169132020-03-23 19:04:55 -0700307 mDownLocation[0] = ev.getRawX();
308 mDownLocation[1] = ev.getRawY();
309 mHandler.postDelayed(mPerformLongPress, mLongPressTimeout);
Michael Jurka21ce2d82011-09-02 15:28:06 -0700310 }
Michael Jurka07d40462011-07-19 10:54:38 -0700311 break;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400312
Michael Jurka07d40462011-07-19 10:54:38 -0700313 case MotionEvent.ACTION_MOVE:
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400314 if (mCurrView != null && !mLongPressSent) {
Michael Jurka07d40462011-07-19 10:54:38 -0700315 mVelocityTracker.addMovement(ev);
316 float pos = getPos(ev);
Jorim Jaggi9b0a2c92016-01-26 18:34:13 -0800317 float perpendicularPos = getPerpendicularPos(ev);
Michael Jurka07d40462011-07-19 10:54:38 -0700318 float delta = pos - mInitialTouchPos;
Jorim Jaggi9b0a2c92016-01-26 18:34:13 -0800319 float deltaPerpendicular = perpendicularPos - mPerpendicularInitialTouchPos;
Philip Quinn47169132020-03-23 19:04:55 -0700320 // Adjust the touch slop if another gesture may be being performed.
321 final float pagingTouchSlop =
322 ev.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
323 ? mPagingTouchSlop * mSlopMultiplier
324 : mPagingTouchSlop;
325 if (Math.abs(delta) > pagingTouchSlop
Jorim Jaggi9b0a2c92016-01-26 18:34:13 -0800326 && Math.abs(delta) > Math.abs(deltaPerpendicular)) {
yoshiki iguchi355692b2018-01-15 11:14:25 +0900327 if (mCallback.canChildBeDragged(mCurrView)) {
328 mCallback.onBeginDrag(mCurrView);
329 mDragging = true;
330 mInitialTouchPos = getPos(ev);
331 mTranslation = getTranslation(mCurrView);
332 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000333 cancelLongPress();
Philip Quinn47169132020-03-23 19:04:55 -0700334 } else if (ev.getClassification() == MotionEvent.CLASSIFICATION_DEEP_PRESS
335 && mHandler.hasCallbacks(mPerformLongPress)) {
336 // Accelerate the long press signal.
337 cancelLongPress();
338 mPerformLongPress.run();
Michael Jurka07d40462011-07-19 10:54:38 -0700339 }
340 }
341 break;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400342
Michael Jurka07d40462011-07-19 10:54:38 -0700343 case MotionEvent.ACTION_UP:
Jeff Brown68ebcdf2011-09-12 14:12:17 -0700344 case MotionEvent.ACTION_CANCEL:
Mady Mellor4ab28202017-06-06 11:42:50 -0700345 final boolean captured = (mDragging || mLongPressSent || mMenuRowIntercepting);
Michael Jurka07d40462011-07-19 10:54:38 -0700346 mDragging = false;
347 mCurrView = null;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400348 mLongPressSent = false;
Mady Mellor4ab28202017-06-06 11:42:50 -0700349 mMenuRowIntercepting = false;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000350 cancelLongPress();
Dan Sandler4247a5c2014-07-23 15:58:08 -0400351 if (captured) return true;
Michael Jurka07d40462011-07-19 10:54:38 -0700352 break;
353 }
Mady Mellor4ab28202017-06-06 11:42:50 -0700354 return mDragging || mLongPressSent || mMenuRowIntercepting;
Michael Jurka07d40462011-07-19 10:54:38 -0700355 }
356
Chet Haase2f2022a2011-10-11 06:41:59 -0700357 /**
358 * @param view The view to be dismissed
359 * @param velocity The desired pixels/second speed at which the view should move
Mady Mellordc6c97d2016-03-31 14:18:35 -0700360 * @param useAccelerateInterpolator Should an accelerating Interpolator be used
Chet Haase2f2022a2011-10-11 06:41:59 -0700361 */
Mady Mellordc6c97d2016-03-31 14:18:35 -0700362 public void dismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
Mady Mellor28796312016-03-08 14:12:42 -0800363 dismissChild(view, velocity, null /* endAction */, 0 /* delay */,
Mady Mellor9c2c4962016-04-05 10:43:08 -0700364 useAccelerateInterpolator, 0 /* fixedDuration */, false /* isDismissAll */);
Dan Sandlereceda3d2014-07-21 15:35:01 -0400365 }
366
367 /**
368 * @param view The view to be dismissed
369 * @param velocity The desired pixels/second speed at which the view should move
370 * @param endAction The action to perform at the end
371 * @param delay The delay after which we should start
372 * @param useAccelerateInterpolator Should an accelerating Interpolator be used
373 * @param fixedDuration If not 0, this exact duration will be taken
374 */
Mady Mellor4b80b102016-01-22 08:03:58 -0800375 public void dismissChild(final View animView, float velocity, final Runnable endAction,
Mady Mellor9c2c4962016-04-05 10:43:08 -0700376 long delay, boolean useAccelerateInterpolator, long fixedDuration,
377 boolean isDismissAll) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800378 final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
Michael Jurka07d40462011-07-19 10:54:38 -0700379 float newPos;
Mady Mellor4b80b102016-01-22 08:03:58 -0800380 boolean isLayoutRtl = animView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
Michael Jurkac6461ca2011-09-02 12:12:15 -0700381
Mady Mellor9c2c4962016-04-05 10:43:08 -0700382 // if we use the Menu to dismiss an item in landscape, animate up
383 boolean animateUpForMenu = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll)
384 && mSwipeDirection == Y;
385 // if the language is rtl we prefer swiping to the left
386 boolean animateLeftForRtl = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll)
387 && isLayoutRtl;
Mady Mellor55744252017-04-10 10:05:17 -0700388 boolean animateLeft = (Math.abs(velocity) > getEscapeVelocity() && velocity < 0) ||
389 (getTranslation(animView) < 0 && !isDismissAll);
Mady Mellor9c2c4962016-04-05 10:43:08 -0700390 if (animateLeft || animateLeftForRtl || animateUpForMenu) {
Michael Jurka07d40462011-07-19 10:54:38 -0700391 newPos = -getSize(animView);
392 } else {
393 newPos = getSize(animView);
394 }
Dan Sandlereceda3d2014-07-21 15:35:01 -0400395 long duration;
396 if (fixedDuration == 0) {
397 duration = MAX_ESCAPE_ANIMATION_DURATION;
398 if (velocity != 0) {
399 duration = Math.min(duration,
400 (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
401 .abs(velocity))
402 );
403 } else {
404 duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
405 }
Michael Jurka0e8063a2011-09-09 15:31:55 -0700406 } else {
Dan Sandlereceda3d2014-07-21 15:35:01 -0400407 duration = fixedDuration;
Michael Jurka07d40462011-07-19 10:54:38 -0700408 }
Michael Jurka0e8063a2011-09-09 15:31:55 -0700409
Winson671e8f92016-01-12 13:16:56 -0800410 if (!mDisableHwLayers) {
411 animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
412 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800413 AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
Mady Mellor43c2cd12016-12-12 21:05:13 -0800414 @Override
Mady Mellor4b80b102016-01-22 08:03:58 -0800415 public void onAnimationUpdate(ValueAnimator animation) {
416 onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
417 }
418 };
419
420 Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
Mady Mellor34958fa2016-02-23 09:52:17 -0800421 if (anim == null) {
422 return;
423 }
Dan Sandlereceda3d2014-07-21 15:35:01 -0400424 if (useAccelerateInterpolator) {
Selim Cinekc18010f2016-01-20 13:41:30 -0800425 anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
Mady Mellor28796312016-03-08 14:12:42 -0800426 anim.setDuration(duration);
Dan Sandlereceda3d2014-07-21 15:35:01 -0400427 } else {
Mady Mellor28796312016-03-08 14:12:42 -0800428 mFlingAnimationUtils.applyDismissing(anim, getTranslation(animView),
429 newPos, velocity, getSize(animView));
Dan Sandlereceda3d2014-07-21 15:35:01 -0400430 }
Dan Sandlereceda3d2014-07-21 15:35:01 -0400431 if (delay > 0) {
432 anim.setStartDelay(delay);
433 }
Chet Haase2f2022a2011-10-11 06:41:59 -0700434 anim.addListener(new AnimatorListenerAdapter() {
dongwan0605.kim30637e42016-03-02 17:16:47 +0900435 private boolean mCancelled;
436
Mady Mellor43c2cd12016-12-12 21:05:13 -0800437 @Override
dongwan0605.kim30637e42016-03-02 17:16:47 +0900438 public void onAnimationCancel(Animator animation) {
439 mCancelled = true;
440 }
441
Mady Mellor43c2cd12016-12-12 21:05:13 -0800442 @Override
Michael Jurka07d40462011-07-19 10:54:38 -0700443 public void onAnimationEnd(Animator animation) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800444 updateSwipeProgressFromOffset(animView, canBeDismissed);
dongwan0605.kim30637e42016-03-02 17:16:47 +0900445 mDismissPendingMap.remove(animView);
Selim Cinekb2e0f332017-08-18 12:24:38 -0700446 boolean wasRemoved = false;
447 if (animView instanceof ExpandableNotificationRow) {
448 ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
449 wasRemoved = row.isRemoved();
450 }
451 if (!mCancelled || wasRemoved) {
dongwan0605.kim30637e42016-03-02 17:16:47 +0900452 mCallback.onChildDismissed(animView);
453 }
Dan Sandlereceda3d2014-07-21 15:35:01 -0400454 if (endAction != null) {
455 endAction.run();
456 }
Winson671e8f92016-01-12 13:16:56 -0800457 if (!mDisableHwLayers) {
458 animView.setLayerType(View.LAYER_TYPE_NONE, null);
459 }
Michael Jurka07d40462011-07-19 10:54:38 -0700460 }
461 });
dongwan0605.kim30637e42016-03-02 17:16:47 +0900462
Winson8aa99592016-01-19 15:07:07 -0800463 prepareDismissAnimation(animView, anim);
dongwan0605.kim30637e42016-03-02 17:16:47 +0900464 mDismissPendingMap.put(animView, anim);
Michael Jurka07d40462011-07-19 10:54:38 -0700465 anim.start();
466 }
467
Winson8aa99592016-01-19 15:07:07 -0800468 /**
469 * Called to update the dismiss animation.
470 */
471 protected void prepareDismissAnimation(View view, Animator anim) {
472 // Do nothing
473 }
474
Mady Mellor4b80b102016-01-22 08:03:58 -0800475 public void snapChild(final View animView, final float targetLeft, float velocity) {
476 final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
477 AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
Mady Mellor43c2cd12016-12-12 21:05:13 -0800478 @Override
Mady Mellor4b80b102016-01-22 08:03:58 -0800479 public void onAnimationUpdate(ValueAnimator animation) {
480 onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
481 }
482 };
483
484 Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
Mady Mellor34958fa2016-02-23 09:52:17 -0800485 if (anim == null) {
486 return;
487 }
Michael Jurka67b03702013-02-15 17:35:48 +0100488 anim.addListener(new AnimatorListenerAdapter() {
Mady Mellor7a5b2b62017-04-14 18:53:45 -0700489 boolean wasCancelled = false;
490
491 @Override
492 public void onAnimationCancel(Animator animator) {
493 wasCancelled = true;
494 }
495
Mady Mellor43c2cd12016-12-12 21:05:13 -0800496 @Override
Michael Jurka67b03702013-02-15 17:35:48 +0100497 public void onAnimationEnd(Animator animator) {
dongwan0605.kim30637e42016-03-02 17:16:47 +0900498 mSnappingChild = false;
Mady Mellor7a5b2b62017-04-14 18:53:45 -0700499 if (!wasCancelled) {
500 updateSwipeProgressFromOffset(animView, canBeDismissed);
Evan Lairde55c6012019-03-13 12:54:37 -0400501 onChildSnappedBack(animView, targetLeft);
Mady Mellor7a5b2b62017-04-14 18:53:45 -0700502 mCallback.onChildSnappedBack(animView, targetLeft);
503 }
Michael Jurka07d40462011-07-19 10:54:38 -0700504 }
505 });
Winson8aa99592016-01-19 15:07:07 -0800506 prepareSnapBackAnimation(animView, anim);
dongwan0605.kim30637e42016-03-02 17:16:47 +0900507 mSnappingChild = true;
Mady Mellor8bdeca02019-02-20 18:34:24 -0800508 float maxDistance = Math.abs(targetLeft - getTranslation(animView));
509 mFlingAnimationUtils.apply(anim, getTranslation(animView), targetLeft, velocity,
510 maxDistance);
Michael Jurka07d40462011-07-19 10:54:38 -0700511 anim.start();
512 }
513
Winsonc5fd3502016-01-18 15:18:37 -0800514 /**
Evan Lairde55c6012019-03-13 12:54:37 -0400515 * Give the swipe helper itself a chance to do something on snap back so NSSL doesn't have
516 * to tell us what to do
517 */
518 protected void onChildSnappedBack(View animView, float targetLeft) {
519 }
520
521 /**
Winsonc5fd3502016-01-18 15:18:37 -0800522 * Called to update the snap back animation.
523 */
Winson8aa99592016-01-19 15:07:07 -0800524 protected void prepareSnapBackAnimation(View view, Animator anim) {
Winsonc5fd3502016-01-18 15:18:37 -0800525 // Do nothing
526 }
527
Mady Mellor4b80b102016-01-22 08:03:58 -0800528 /**
529 * Called when there's a down event.
530 */
Mady Mellor95d743c2017-01-10 12:05:27 -0800531 public void onDownUpdate(View currView, MotionEvent ev) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800532 // Do nothing
533 }
534
535 /**
536 * Called on a move event.
537 */
Mady Mellor95d743c2017-01-10 12:05:27 -0800538 protected void onMoveUpdate(View view, MotionEvent ev, float totalTranslation, float delta) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800539 // Do nothing
540 }
541
542 /**
543 * Called in {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)} when the current
544 * view is being animated to dismiss or snap.
545 */
546 public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
Winsonbde852d2016-04-15 19:06:54 -0700547 updateSwipeProgressFromOffset(animView, canBeDismissed, value);
Mady Mellor4b80b102016-01-22 08:03:58 -0800548 }
549
dongwan0605.kim30637e42016-03-02 17:16:47 +0900550 private void snapChildInstantly(final View view) {
551 final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
552 setTranslation(view, 0);
553 updateSwipeProgressFromOffset(view, canAnimViewBeDismissed);
554 }
555
Mady Mellor86889c22016-04-18 16:37:06 -0700556 /**
557 * Called when a view is updated to be non-dismissable, if the view was being dismissed before
558 * the update this will handle snapping it back into place.
559 *
560 * @param view the view to snap if necessary.
561 * @param animate whether to animate the snap or not.
562 * @param targetLeft the target to snap to.
563 */
564 public void snapChildIfNeeded(final View view, boolean animate, float targetLeft) {
dongwan0605.kim30637e42016-03-02 17:16:47 +0900565 if ((mDragging && mCurrView == view) || mSnappingChild) {
566 return;
567 }
568 boolean needToSnap = false;
569 Animator dismissPendingAnim = mDismissPendingMap.get(view);
570 if (dismissPendingAnim != null) {
571 needToSnap = true;
572 dismissPendingAnim.cancel();
573 } else if (getTranslation(view) != 0) {
574 needToSnap = true;
575 }
576 if (needToSnap) {
577 if (animate) {
Mady Mellor86889c22016-04-18 16:37:06 -0700578 snapChild(view, targetLeft, 0.0f /* velocity */);
dongwan0605.kim30637e42016-03-02 17:16:47 +0900579 } else {
580 snapChildInstantly(view);
581 }
582 }
583 }
584
Mady Mellor43c2cd12016-12-12 21:05:13 -0800585 @Override
Michael Jurka07d40462011-07-19 10:54:38 -0700586 public boolean onTouchEvent(MotionEvent ev) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700587 if (mLongPressSent && !mMenuRowIntercepting) {
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400588 return true;
589 }
590
Mady Mellor4ab28202017-06-06 11:42:50 -0700591 if (!mDragging && !mMenuRowIntercepting) {
Jorim Jaggi28f0e592014-08-05 22:03:07 +0200592 if (mCallback.getChildAtPosition(ev) != null) {
593
594 // We are dragging directly over a card, make sure that we also catch the gesture
595 // even if nobody else wants the touch event.
596 onInterceptTouchEvent(ev);
597 return true;
598 } else {
599
600 // We are not doing anything, make sure the long press callback
601 // is not still ticking like a bomb waiting to go off.
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000602 cancelLongPress();
Jorim Jaggi28f0e592014-08-05 22:03:07 +0200603 return false;
604 }
Michael Jurka07d40462011-07-19 10:54:38 -0700605 }
606
607 mVelocityTracker.addMovement(ev);
608 final int action = ev.getAction();
609 switch (action) {
610 case MotionEvent.ACTION_OUTSIDE:
611 case MotionEvent.ACTION_MOVE:
612 if (mCurrView != null) {
613 float delta = getPos(ev) - mInitialTouchPos;
Selim Cinek19c8c702014-08-25 22:09:19 +0200614 float absDelta = Math.abs(delta);
Selim Cinek34cf5c42014-09-26 15:39:00 +0200615 if (absDelta >= getFalsingThreshold()) {
Selim Cinek19c8c702014-08-25 22:09:19 +0200616 mTouchAboveFalsingThreshold = true;
617 }
Michael Jurka07d40462011-07-19 10:54:38 -0700618 // don't let items that can't be dismissed be dragged more than
619 // maxScrollDistance
Gus Prevas37d67e22018-11-02 14:48:55 -0400620 if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissedInDirection(mCurrView,
621 delta > 0)) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800622 float size = getSize(mCurrView);
Mady Mellor55744252017-04-10 10:05:17 -0700623 float maxScrollDistance = MAX_SCROLL_SIZE_FRACTION * size;
Selim Cinek19c8c702014-08-25 22:09:19 +0200624 if (absDelta >= size) {
Michael Jurka07d40462011-07-19 10:54:38 -0700625 delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
626 } else {
Gus Prevasc4e68d42019-01-17 15:45:21 -0500627 int startPosition = mCallback.getConstrainSwipeStartPosition();
628 if (absDelta > startPosition) {
629 int signedStartPosition =
630 (int) (startPosition * Math.signum(delta));
631 delta = signedStartPosition
632 + maxScrollDistance * (float) Math.sin(
633 ((delta - signedStartPosition) / size) * (Math.PI / 2));
634 }
Michael Jurka07d40462011-07-19 10:54:38 -0700635 }
636 }
Michael Jurka67b03702013-02-15 17:35:48 +0100637
Mady Mellor4b80b102016-01-22 08:03:58 -0800638 setTranslation(mCurrView, mTranslation + delta);
639 updateSwipeProgressFromOffset(mCurrView, mCanCurrViewBeDimissed);
Mady Mellor95d743c2017-01-10 12:05:27 -0800640 onMoveUpdate(mCurrView, ev, mTranslation + delta, delta);
Michael Jurka07d40462011-07-19 10:54:38 -0700641 }
642 break;
643 case MotionEvent.ACTION_UP:
644 case MotionEvent.ACTION_CANCEL:
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000645 if (mCurrView == null) {
646 break;
647 }
648 mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, getMaxVelocity());
649 float velocity = getVelocity(mVelocityTracker);
Michael Jurka07d40462011-07-19 10:54:38 -0700650
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000651 if (!handleUpEvent(ev, mCurrView, velocity, getTranslation(mCurrView))) {
652 if (isDismissGesture(ev)) {
Michael Jurka07d40462011-07-19 10:54:38 -0700653 // flingadingy
Mady Mellordc6c97d2016-03-31 14:18:35 -0700654 dismissChild(mCurrView, velocity,
655 !swipedFastEnough() /* useAccelerateInterpolator */);
Michael Jurka07d40462011-07-19 10:54:38 -0700656 } else {
657 // snappity
Peter Ng622a9762011-08-29 10:56:53 -0700658 mCallback.onDragCancelled(mCurrView);
Mady Mellor4b80b102016-01-22 08:03:58 -0800659 snapChild(mCurrView, 0 /* leftTarget */, velocity);
Michael Jurka07d40462011-07-19 10:54:38 -0700660 }
dongwan0605.kim30637e42016-03-02 17:16:47 +0900661 mCurrView = null;
Michael Jurka07d40462011-07-19 10:54:38 -0700662 }
dongwan0605.kim30637e42016-03-02 17:16:47 +0900663 mDragging = false;
Michael Jurka07d40462011-07-19 10:54:38 -0700664 break;
665 }
666 return true;
667 }
668
Selim Cinek34cf5c42014-09-26 15:39:00 +0200669 private int getFalsingThreshold() {
670 float factor = mCallback.getFalsingThresholdFactor();
671 return (int) (mFalsingThreshold * factor);
672 }
673
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000674 private float getMaxVelocity() {
675 return MAX_DISMISS_VELOCITY * mDensityScale;
676 }
677
678 protected float getEscapeVelocity() {
Winsonbde852d2016-04-15 19:06:54 -0700679 return getUnscaledEscapeVelocity() * mDensityScale;
680 }
681
682 protected float getUnscaledEscapeVelocity() {
683 return SWIPE_ESCAPE_VELOCITY;
684 }
685
686 protected long getMaxEscapeAnimDuration() {
687 return MAX_ESCAPE_ANIMATION_DURATION;
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000688 }
689
690 protected boolean swipedFarEnough() {
691 float translation = getTranslation(mCurrView);
Mady Mellor55744252017-04-10 10:05:17 -0700692 return DISMISS_IF_SWIPED_FAR_ENOUGH
693 && Math.abs(translation) > SWIPED_FAR_ENOUGH_SIZE_FRACTION * getSize(mCurrView);
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000694 }
695
Mady Mellor95d743c2017-01-10 12:05:27 -0800696 public boolean isDismissGesture(MotionEvent ev) {
Gus Prevas37d67e22018-11-02 14:48:55 -0400697 float translation = getTranslation(mCurrView);
Mady Mellorbd707492017-05-10 17:51:25 -0700698 return ev.getActionMasked() == MotionEvent.ACTION_UP
Dave Mankoffc88d6222018-10-25 15:31:20 -0400699 && !mFalsingManager.isUnlockingDisabled()
Mady Mellorbd707492017-05-10 17:51:25 -0700700 && !isFalseGesture(ev) && (swipedFastEnough() || swipedFarEnough())
Gus Prevas37d67e22018-11-02 14:48:55 -0400701 && mCallback.canChildBeDismissedInDirection(mCurrView, translation > 0);
Mady Mellorbd707492017-05-10 17:51:25 -0700702 }
703
704 public boolean isFalseGesture(MotionEvent ev) {
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000705 boolean falsingDetected = mCallback.isAntiFalsingNeeded();
Dave Mankoff9febfeb2019-12-18 12:18:00 -0500706 if (mFalsingManager.isClassifierEnabled()) {
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000707 falsingDetected = falsingDetected && mFalsingManager.isFalseTouch();
708 } else {
709 falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold;
710 }
Mady Mellorbd707492017-05-10 17:51:25 -0700711 return falsingDetected;
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000712 }
713
714 protected boolean swipedFastEnough() {
715 float velocity = getVelocity(mVelocityTracker);
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000716 float translation = getTranslation(mCurrView);
Mady Mellordc6c97d2016-03-31 14:18:35 -0700717 boolean ret = (Math.abs(velocity) > getEscapeVelocity())
718 && (velocity > 0) == (translation > 0);
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000719 return ret;
720 }
721
722 protected boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
723 float translation) {
724 return false;
725 }
726
Michael Jurka07d40462011-07-19 10:54:38 -0700727 public interface Callback {
728 View getChildAtPosition(MotionEvent ev);
729
Michael Jurka07d40462011-07-19 10:54:38 -0700730 boolean canChildBeDismissed(View v);
731
Gus Prevas37d67e22018-11-02 14:48:55 -0400732 /**
733 * Returns true if the provided child can be dismissed by a swipe in the given direction.
734 *
735 * @param isRightOrDown {@code true} if the swipe direction is right or down,
736 * {@code false} if it is left or up.
737 */
738 default boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
739 return canChildBeDismissed(v);
740 }
741
Selim Cinek19c8c702014-08-25 22:09:19 +0200742 boolean isAntiFalsingNeeded();
743
Michael Jurka07d40462011-07-19 10:54:38 -0700744 void onBeginDrag(View v);
745
746 void onChildDismissed(View v);
Peter Ng622a9762011-08-29 10:56:53 -0700747
748 void onDragCancelled(View v);
Selim Cinekeb973562014-05-02 17:07:49 +0200749
Mady Mellor4b80b102016-01-22 08:03:58 -0800750 /**
751 * Called when the child is snapped to a position.
752 *
753 * @param animView the view that was snapped.
754 * @param targetLeft the left position the view was snapped to.
755 */
756 void onChildSnappedBack(View animView, float targetLeft);
Adrian Roos5d9cc662014-05-28 17:08:13 +0200757
758 /**
759 * Updates the swipe progress on a child.
760 *
761 * @return if true, prevents the default alpha fading.
762 */
763 boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress);
Selim Cinek34cf5c42014-09-26 15:39:00 +0200764
765 /**
766 * @return The factor the falsing threshold should be multiplied with
767 */
768 float getFalsingThresholdFactor();
yoshiki iguchi355692b2018-01-15 11:14:25 +0900769
770 /**
Gus Prevasc4e68d42019-01-17 15:45:21 -0500771 * @return The position, in pixels, at which a constrained swipe should start being
772 * constrained.
773 */
774 default int getConstrainSwipeStartPosition() {
775 return 0;
776 }
777
778 /**
yoshiki iguchi355692b2018-01-15 11:14:25 +0900779 * @return If true, the given view is draggable.
780 */
781 default boolean canChildBeDragged(@NonNull View animView) { return true; }
Michael Jurka07d40462011-07-19 10:54:38 -0700782 }
Michael Jurka07d40462011-07-19 10:54:38 -0700783}