blob: 84e0238fdd3a9e130f6cb82ffae37d2a9b65ae78 [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 Mankoffdde5ee62019-05-02 17:36:11 -040037import com.android.systemui.classifier.FalsingManagerFactory;
Dave Mankoff468d4f62019-05-08 14:56:29 -040038import com.android.systemui.plugins.FalsingManager;
Mady Mellor4ab28202017-06-06 11:42:50 -070039import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
Mady Mellor28796312016-03-08 14:12:42 -080040import com.android.systemui.statusbar.FlingAnimationUtils;
Gus Prevas37d67e22018-11-02 14:48:55 -040041import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Blazej Magnowski6dc59b42015-09-22 15:14:20 -070042
Daniel Sandler6a858c32012-03-12 14:38:58 -040043public class SwipeHelper implements Gefingerpoken {
Michael Jurka07d40462011-07-19 10:54:38 -070044 static final String TAG = "com.android.systemui.SwipeHelper";
Daniel Sandler96f48182011-08-17 09:50:35 -040045 private static final boolean DEBUG = false;
Michael Jurka07d40462011-07-19 10:54:38 -070046 private static final boolean DEBUG_INVALIDATE = false;
47 private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
Michael Jurka3cd0a592011-08-16 12:40:30 -070048 private static final boolean CONSTRAIN_SWIPE = true;
49 private static final boolean FADE_OUT_DURING_SWIPE = true;
50 private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
Michael Jurka07d40462011-07-19 10:54:38 -070051
52 public static final int X = 0;
53 public static final int Y = 1;
54
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070055 private static final float SWIPE_ESCAPE_VELOCITY = 500f; // dp/sec
56 private static final int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
57 private static final int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
58 private static final int MAX_DISMISS_VELOCITY = 4000; // dp/sec
Michael Jurka0e8063a2011-09-09 15:31:55 -070059 private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
Michael Jurka07d40462011-07-19 10:54:38 -070060
Adrian Roos5d9cc662014-05-28 17:08:13 +020061 static final float SWIPE_PROGRESS_FADE_END = 0.5f; // fraction of thumbnail width
62 // beyond which swipe progress->0
Mady Mellor55744252017-04-10 10:05:17 -070063 public static final float SWIPED_FAR_ENOUGH_SIZE_FRACTION = 0.6f;
64 static final float MAX_SCROLL_SIZE_FRACTION = 0.3f;
65
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040066 protected final Handler mHandler;
67
Adrian Roos5d9cc662014-05-28 17:08:13 +020068 private float mMinSwipeProgress = 0f;
69 private float mMaxSwipeProgress = 1f;
Michael Jurka07d40462011-07-19 10:54:38 -070070
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070071 private final FlingAnimationUtils mFlingAnimationUtils;
Michael Jurka07d40462011-07-19 10:54:38 -070072 private float mPagingTouchSlop;
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;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040088 private boolean mLongPressSent;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040089 private Runnable mWatchLongPress;
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070090 private final long mLongPressTimeout;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040091
Dan Sandler4247a5c2014-07-23 15:58:08 -040092 final private int[] mTmpPos = new int[2];
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070093 private final int mFalsingThreshold;
Selim Cinek19c8c702014-08-25 22:09:19 +020094 private boolean mTouchAboveFalsingThreshold;
Winson671e8f92016-01-12 13:16:56 -080095 private boolean mDisableHwLayers;
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070096 private final boolean mFadeDependingOnAmountSwiped;
97 private final Context mContext;
Dan Sandler4247a5c2014-07-23 15:58:08 -040098
Rajeev Kumar7c8bc0f2017-06-13 16:22:57 -070099 private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
dongwan0605.kim30637e42016-03-02 17:16:47 +0900100
Dan Sandlereceda3d2014-07-21 15:35:01 -0400101 public SwipeHelper(int swipeDirection, Callback callback, Context context) {
Mady Mellor43c2cd12016-12-12 21:05:13 -0800102 mContext = context;
Michael Jurka07d40462011-07-19 10:54:38 -0700103 mCallback = callback;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400104 mHandler = new Handler();
Michael Jurka07d40462011-07-19 10:54:38 -0700105 mSwipeDirection = swipeDirection;
106 mVelocityTracker = VelocityTracker.obtain();
Dan Sandlereceda3d2014-07-21 15:35:01 -0400107 mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
Daniel Sandler469e96e2012-05-04 15:56:19 -0400108
Anthony Chen7acbb772017-04-07 16:45:25 -0700109 // Extra long-press!
110 mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
111
112 Resources res = context.getResources();
113 mDensityScale = res.getDisplayMetrics().density;
114 mFalsingThreshold = res.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
115 mFadeDependingOnAmountSwiped = res.getBoolean(R.bool.config_fadeDependingOnAmountSwiped);
Dave Mankoffdde5ee62019-05-02 17:36:11 -0400116 mFalsingManager = FalsingManagerFactory.getInstance(context);
Winsonbde852d2016-04-15 19:06:54 -0700117 mFlingAnimationUtils = new FlingAnimationUtils(context, getMaxEscapeAnimDuration() / 1000f);
Michael Jurka07d40462011-07-19 10:54:38 -0700118 }
119
120 public void setDensityScale(float densityScale) {
121 mDensityScale = densityScale;
122 }
123
124 public void setPagingTouchSlop(float pagingTouchSlop) {
125 mPagingTouchSlop = pagingTouchSlop;
126 }
127
Winson671e8f92016-01-12 13:16:56 -0800128 public void setDisableHardwareLayers(boolean disableHwLayers) {
129 mDisableHwLayers = disableHwLayers;
130 }
131
Michael Jurka07d40462011-07-19 10:54:38 -0700132 private float getPos(MotionEvent ev) {
133 return mSwipeDirection == X ? ev.getX() : ev.getY();
134 }
135
Jorim Jaggi9b0a2c92016-01-26 18:34:13 -0800136 private float getPerpendicularPos(MotionEvent ev) {
137 return mSwipeDirection == X ? ev.getY() : ev.getX();
138 }
139
Mady Mellor4b80b102016-01-22 08:03:58 -0800140 protected float getTranslation(View v) {
Michael Jurka3cd0a592011-08-16 12:40:30 -0700141 return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
Michael Jurka07d40462011-07-19 10:54:38 -0700142 }
143
144 private float getVelocity(VelocityTracker vt) {
145 return mSwipeDirection == X ? vt.getXVelocity() :
146 vt.getYVelocity();
147 }
148
Mady Mellor4b80b102016-01-22 08:03:58 -0800149 protected ObjectAnimator createTranslationAnimation(View v, float newPos) {
Michael Jurka07d40462011-07-19 10:54:38 -0700150 ObjectAnimator anim = ObjectAnimator.ofFloat(v,
Winsonc5fd3502016-01-18 15:18:37 -0800151 mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
Michael Jurka07d40462011-07-19 10:54:38 -0700152 return anim;
153 }
154
155 private float getPerpendicularVelocity(VelocityTracker vt) {
156 return mSwipeDirection == X ? vt.getYVelocity() :
157 vt.getXVelocity();
158 }
159
Mady Mellor4b80b102016-01-22 08:03:58 -0800160 protected Animator getViewTranslationAnimator(View v, float target,
161 AnimatorUpdateListener listener) {
162 ObjectAnimator anim = createTranslationAnimation(v, target);
Mady Mellor34958fa2016-02-23 09:52:17 -0800163 if (listener != null) {
164 anim.addUpdateListener(listener);
165 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800166 return anim;
167 }
168
169 protected void setTranslation(View v, float translate) {
170 if (v == null) {
171 return;
172 }
Michael Jurka07d40462011-07-19 10:54:38 -0700173 if (mSwipeDirection == X) {
174 v.setTranslationX(translate);
175 } else {
176 v.setTranslationY(translate);
177 }
178 }
179
Winson671e8f92016-01-12 13:16:56 -0800180 protected float getSize(View v) {
Anthony Chen7acbb772017-04-07 16:45:25 -0700181 return mSwipeDirection == X ? v.getMeasuredWidth() : v.getMeasuredHeight();
Michael Jurka07d40462011-07-19 10:54:38 -0700182 }
183
Adrian Roos5d9cc662014-05-28 17:08:13 +0200184 public void setMinSwipeProgress(float minSwipeProgress) {
185 mMinSwipeProgress = minSwipeProgress;
Michael Jurka4eaa9832012-02-29 15:51:49 -0800186 }
187
Adrian Roos5d9cc662014-05-28 17:08:13 +0200188 public void setMaxSwipeProgress(float maxSwipeProgress) {
189 mMaxSwipeProgress = maxSwipeProgress;
Adrian Roosde61fd72014-05-26 14:59:15 +0200190 }
191
Winsonbde852d2016-04-15 19:06:54 -0700192 private float getSwipeProgressForOffset(View view, float translation) {
Michael Jurka3cd0a592011-08-16 12:40:30 -0700193 float viewSize = getSize(view);
Winsonbde852d2016-04-15 19:06:54 -0700194 float result = Math.abs(translation / viewSize);
Adrian Roos5d9cc662014-05-28 17:08:13 +0200195 return Math.min(Math.max(mMinSwipeProgress, result), mMaxSwipeProgress);
Michael Jurka07d40462011-07-19 10:54:38 -0700196 }
197
Winsonbde852d2016-04-15 19:06:54 -0700198 private float getSwipeAlpha(float progress) {
Anthony Chen7acbb772017-04-07 16:45:25 -0700199 if (mFadeDependingOnAmountSwiped) {
200 // The more progress has been fade, the lower the alpha value so that the view fades.
201 return Math.max(1 - progress, 0);
202 }
203
Winson Chungd8a52f22017-08-10 14:13:37 -0700204 return 1f - Math.max(0, Math.min(1, progress / SWIPE_PROGRESS_FADE_END));
Winsonbde852d2016-04-15 19:06:54 -0700205 }
206
Adrian Roos5d9cc662014-05-28 17:08:13 +0200207 private void updateSwipeProgressFromOffset(View animView, boolean dismissable) {
Winsonbde852d2016-04-15 19:06:54 -0700208 updateSwipeProgressFromOffset(animView, dismissable, getTranslation(animView));
209 }
210
211 private void updateSwipeProgressFromOffset(View animView, boolean dismissable,
212 float translation) {
213 float swipeProgress = getSwipeProgressForOffset(animView, translation);
Adrian Roos5d9cc662014-05-28 17:08:13 +0200214 if (!mCallback.updateSwipeProgress(animView, dismissable, swipeProgress)) {
215 if (FADE_OUT_DURING_SWIPE && dismissable) {
Winson671e8f92016-01-12 13:16:56 -0800216 if (!mDisableHwLayers) {
Anthony Chen7acbb772017-04-07 16:45:25 -0700217 if (swipeProgress != 0f && swipeProgress != 1f) {
Winson671e8f92016-01-12 13:16:56 -0800218 animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
219 } else {
220 animView.setLayerType(View.LAYER_TYPE_NONE, null);
221 }
Adrian Roos5d9cc662014-05-28 17:08:13 +0200222 }
Winsonbde852d2016-04-15 19:06:54 -0700223 animView.setAlpha(getSwipeAlpha(swipeProgress));
Michael Jurka499293f2013-03-06 18:08:45 +0100224 }
Michael Jurka67b03702013-02-15 17:35:48 +0100225 }
226 invalidateGlobalRegion(animView);
227 }
228
Daniel Sandlera375c942011-07-29 00:33:53 -0400229 // invalidate the view's own bounds all the way up the view hierarchy
230 public static void invalidateGlobalRegion(View view) {
231 invalidateGlobalRegion(
232 view,
233 new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
234 }
235
236 // invalidate a rectangle relative to the view's coordinate system all the way up the view
237 // hierarchy
238 public static void invalidateGlobalRegion(View view, RectF childBounds) {
Daniel Sandler96f48182011-08-17 09:50:35 -0400239 //childBounds.offset(view.getTranslationX(), view.getTranslationY());
Michael Jurka07d40462011-07-19 10:54:38 -0700240 if (DEBUG_INVALIDATE)
241 Log.v(TAG, "-------------");
242 while (view.getParent() != null && view.getParent() instanceof View) {
243 view = (View) view.getParent();
244 view.getMatrix().mapRect(childBounds);
245 view.invalidate((int) Math.floor(childBounds.left),
246 (int) Math.floor(childBounds.top),
247 (int) Math.ceil(childBounds.right),
248 (int) Math.ceil(childBounds.bottom));
249 if (DEBUG_INVALIDATE) {
250 Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
251 + "," + (int) Math.floor(childBounds.top)
252 + "," + (int) Math.ceil(childBounds.right)
253 + "," + (int) Math.ceil(childBounds.bottom));
254 }
255 }
256 }
257
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000258 public void cancelLongPress() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400259 if (mWatchLongPress != null) {
260 mHandler.removeCallbacks(mWatchLongPress);
Daniel Sandler491d3a92012-05-16 13:04:06 -0400261 mWatchLongPress = null;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400262 }
263 }
264
Mady Mellor43c2cd12016-12-12 21:05:13 -0800265 @Override
Dan Sandler4247a5c2014-07-23 15:58:08 -0400266 public boolean onInterceptTouchEvent(final MotionEvent ev) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700267 if (mCurrView instanceof ExpandableNotificationRow) {
268 NotificationMenuRowPlugin nmr = ((ExpandableNotificationRow) mCurrView).getProvider();
Evan Lairde55c6012019-03-13 12:54:37 -0400269 if (nmr != null) {
270 mMenuRowIntercepting = nmr.onInterceptTouchEvent(mCurrView, ev);
271 }
Mady Mellor4ab28202017-06-06 11:42:50 -0700272 }
Michael Jurka07d40462011-07-19 10:54:38 -0700273 final int action = ev.getAction();
274
275 switch (action) {
276 case MotionEvent.ACTION_DOWN:
Selim Cinek19c8c702014-08-25 22:09:19 +0200277 mTouchAboveFalsingThreshold = false;
Michael Jurka07d40462011-07-19 10:54:38 -0700278 mDragging = false;
dongwan0605.kim30637e42016-03-02 17:16:47 +0900279 mSnappingChild = false;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400280 mLongPressSent = false;
Michael Jurka07d40462011-07-19 10:54:38 -0700281 mVelocityTracker.clear();
Mady Mellor4b80b102016-01-22 08:03:58 -0800282 mCurrView = mCallback.getChildAtPosition(ev);
283
Michael Jurka21ce2d82011-09-02 15:28:06 -0700284 if (mCurrView != null) {
Mady Mellor95d743c2017-01-10 12:05:27 -0800285 onDownUpdate(mCurrView, ev);
Michael Jurka21ce2d82011-09-02 15:28:06 -0700286 mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
287 mVelocityTracker.addMovement(ev);
288 mInitialTouchPos = getPos(ev);
Jorim Jaggi9b0a2c92016-01-26 18:34:13 -0800289 mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
Mady Mellor4b80b102016-01-22 08:03:58 -0800290 mTranslation = getTranslation(mCurrView);
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000291 if (mWatchLongPress == null) {
292 mWatchLongPress = new Runnable() {
293 @Override
294 public void run() {
295 if (mCurrView != null && !mLongPressSent) {
296 mLongPressSent = true;
297 mCurrView.getLocationOnScreen(mTmpPos);
298 final int x = (int) ev.getRawX() - mTmpPos[0];
299 final int y = (int) ev.getRawY() - mTmpPos[1];
300 if (mCurrView instanceof ExpandableNotificationRow) {
Selim Cinek464d0d92017-08-25 22:07:36 +0000301 mCurrView.sendAccessibilityEvent(
302 AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000303 ExpandableNotificationRow currRow =
304 (ExpandableNotificationRow) mCurrView;
305 currRow.doLongClickCallback(x, y);
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400306 }
307 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000308 }
309 };
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400310 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000311 mHandler.postDelayed(mWatchLongPress, mLongPressTimeout);
Michael Jurka21ce2d82011-09-02 15:28:06 -0700312 }
Michael Jurka07d40462011-07-19 10:54:38 -0700313 break;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400314
Michael Jurka07d40462011-07-19 10:54:38 -0700315 case MotionEvent.ACTION_MOVE:
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400316 if (mCurrView != null && !mLongPressSent) {
Michael Jurka07d40462011-07-19 10:54:38 -0700317 mVelocityTracker.addMovement(ev);
318 float pos = getPos(ev);
Jorim Jaggi9b0a2c92016-01-26 18:34:13 -0800319 float perpendicularPos = getPerpendicularPos(ev);
Michael Jurka07d40462011-07-19 10:54:38 -0700320 float delta = pos - mInitialTouchPos;
Jorim Jaggi9b0a2c92016-01-26 18:34:13 -0800321 float deltaPerpendicular = perpendicularPos - mPerpendicularInitialTouchPos;
322 if (Math.abs(delta) > mPagingTouchSlop
323 && Math.abs(delta) > Math.abs(deltaPerpendicular)) {
yoshiki iguchi355692b2018-01-15 11:14:25 +0900324 if (mCallback.canChildBeDragged(mCurrView)) {
325 mCallback.onBeginDrag(mCurrView);
326 mDragging = true;
327 mInitialTouchPos = getPos(ev);
328 mTranslation = getTranslation(mCurrView);
329 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000330 cancelLongPress();
Michael Jurka07d40462011-07-19 10:54:38 -0700331 }
332 }
333 break;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400334
Michael Jurka07d40462011-07-19 10:54:38 -0700335 case MotionEvent.ACTION_UP:
Jeff Brown68ebcdf2011-09-12 14:12:17 -0700336 case MotionEvent.ACTION_CANCEL:
Mady Mellor4ab28202017-06-06 11:42:50 -0700337 final boolean captured = (mDragging || mLongPressSent || mMenuRowIntercepting);
Michael Jurka07d40462011-07-19 10:54:38 -0700338 mDragging = false;
339 mCurrView = null;
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400340 mLongPressSent = false;
Mady Mellor4ab28202017-06-06 11:42:50 -0700341 mMenuRowIntercepting = false;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000342 cancelLongPress();
Dan Sandler4247a5c2014-07-23 15:58:08 -0400343 if (captured) return true;
Michael Jurka07d40462011-07-19 10:54:38 -0700344 break;
345 }
Mady Mellor4ab28202017-06-06 11:42:50 -0700346 return mDragging || mLongPressSent || mMenuRowIntercepting;
Michael Jurka07d40462011-07-19 10:54:38 -0700347 }
348
Chet Haase2f2022a2011-10-11 06:41:59 -0700349 /**
350 * @param view The view to be dismissed
351 * @param velocity The desired pixels/second speed at which the view should move
Mady Mellordc6c97d2016-03-31 14:18:35 -0700352 * @param useAccelerateInterpolator Should an accelerating Interpolator be used
Chet Haase2f2022a2011-10-11 06:41:59 -0700353 */
Mady Mellordc6c97d2016-03-31 14:18:35 -0700354 public void dismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
Mady Mellor28796312016-03-08 14:12:42 -0800355 dismissChild(view, velocity, null /* endAction */, 0 /* delay */,
Mady Mellor9c2c4962016-04-05 10:43:08 -0700356 useAccelerateInterpolator, 0 /* fixedDuration */, false /* isDismissAll */);
Dan Sandlereceda3d2014-07-21 15:35:01 -0400357 }
358
359 /**
360 * @param view The view to be dismissed
361 * @param velocity The desired pixels/second speed at which the view should move
362 * @param endAction The action to perform at the end
363 * @param delay The delay after which we should start
364 * @param useAccelerateInterpolator Should an accelerating Interpolator be used
365 * @param fixedDuration If not 0, this exact duration will be taken
366 */
Mady Mellor4b80b102016-01-22 08:03:58 -0800367 public void dismissChild(final View animView, float velocity, final Runnable endAction,
Mady Mellor9c2c4962016-04-05 10:43:08 -0700368 long delay, boolean useAccelerateInterpolator, long fixedDuration,
369 boolean isDismissAll) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800370 final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
Michael Jurka07d40462011-07-19 10:54:38 -0700371 float newPos;
Mady Mellor4b80b102016-01-22 08:03:58 -0800372 boolean isLayoutRtl = animView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
Michael Jurkac6461ca2011-09-02 12:12:15 -0700373
Mady Mellor9c2c4962016-04-05 10:43:08 -0700374 // if we use the Menu to dismiss an item in landscape, animate up
375 boolean animateUpForMenu = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll)
376 && mSwipeDirection == Y;
377 // if the language is rtl we prefer swiping to the left
378 boolean animateLeftForRtl = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll)
379 && isLayoutRtl;
Mady Mellor55744252017-04-10 10:05:17 -0700380 boolean animateLeft = (Math.abs(velocity) > getEscapeVelocity() && velocity < 0) ||
381 (getTranslation(animView) < 0 && !isDismissAll);
Mady Mellor9c2c4962016-04-05 10:43:08 -0700382 if (animateLeft || animateLeftForRtl || animateUpForMenu) {
Michael Jurka07d40462011-07-19 10:54:38 -0700383 newPos = -getSize(animView);
384 } else {
385 newPos = getSize(animView);
386 }
Dan Sandlereceda3d2014-07-21 15:35:01 -0400387 long duration;
388 if (fixedDuration == 0) {
389 duration = MAX_ESCAPE_ANIMATION_DURATION;
390 if (velocity != 0) {
391 duration = Math.min(duration,
392 (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
393 .abs(velocity))
394 );
395 } else {
396 duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
397 }
Michael Jurka0e8063a2011-09-09 15:31:55 -0700398 } else {
Dan Sandlereceda3d2014-07-21 15:35:01 -0400399 duration = fixedDuration;
Michael Jurka07d40462011-07-19 10:54:38 -0700400 }
Michael Jurka0e8063a2011-09-09 15:31:55 -0700401
Winson671e8f92016-01-12 13:16:56 -0800402 if (!mDisableHwLayers) {
403 animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
404 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800405 AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
Mady Mellor43c2cd12016-12-12 21:05:13 -0800406 @Override
Mady Mellor4b80b102016-01-22 08:03:58 -0800407 public void onAnimationUpdate(ValueAnimator animation) {
408 onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
409 }
410 };
411
412 Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
Mady Mellor34958fa2016-02-23 09:52:17 -0800413 if (anim == null) {
414 return;
415 }
Dan Sandlereceda3d2014-07-21 15:35:01 -0400416 if (useAccelerateInterpolator) {
Selim Cinekc18010f2016-01-20 13:41:30 -0800417 anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
Mady Mellor28796312016-03-08 14:12:42 -0800418 anim.setDuration(duration);
Dan Sandlereceda3d2014-07-21 15:35:01 -0400419 } else {
Mady Mellor28796312016-03-08 14:12:42 -0800420 mFlingAnimationUtils.applyDismissing(anim, getTranslation(animView),
421 newPos, velocity, getSize(animView));
Dan Sandlereceda3d2014-07-21 15:35:01 -0400422 }
Dan Sandlereceda3d2014-07-21 15:35:01 -0400423 if (delay > 0) {
424 anim.setStartDelay(delay);
425 }
Chet Haase2f2022a2011-10-11 06:41:59 -0700426 anim.addListener(new AnimatorListenerAdapter() {
dongwan0605.kim30637e42016-03-02 17:16:47 +0900427 private boolean mCancelled;
428
Mady Mellor43c2cd12016-12-12 21:05:13 -0800429 @Override
dongwan0605.kim30637e42016-03-02 17:16:47 +0900430 public void onAnimationCancel(Animator animation) {
431 mCancelled = true;
432 }
433
Mady Mellor43c2cd12016-12-12 21:05:13 -0800434 @Override
Michael Jurka07d40462011-07-19 10:54:38 -0700435 public void onAnimationEnd(Animator animation) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800436 updateSwipeProgressFromOffset(animView, canBeDismissed);
dongwan0605.kim30637e42016-03-02 17:16:47 +0900437 mDismissPendingMap.remove(animView);
Selim Cinekb2e0f332017-08-18 12:24:38 -0700438 boolean wasRemoved = false;
439 if (animView instanceof ExpandableNotificationRow) {
440 ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
441 wasRemoved = row.isRemoved();
442 }
443 if (!mCancelled || wasRemoved) {
dongwan0605.kim30637e42016-03-02 17:16:47 +0900444 mCallback.onChildDismissed(animView);
445 }
Dan Sandlereceda3d2014-07-21 15:35:01 -0400446 if (endAction != null) {
447 endAction.run();
448 }
Winson671e8f92016-01-12 13:16:56 -0800449 if (!mDisableHwLayers) {
450 animView.setLayerType(View.LAYER_TYPE_NONE, null);
451 }
Michael Jurka07d40462011-07-19 10:54:38 -0700452 }
453 });
dongwan0605.kim30637e42016-03-02 17:16:47 +0900454
Winson8aa99592016-01-19 15:07:07 -0800455 prepareDismissAnimation(animView, anim);
dongwan0605.kim30637e42016-03-02 17:16:47 +0900456 mDismissPendingMap.put(animView, anim);
Michael Jurka07d40462011-07-19 10:54:38 -0700457 anim.start();
458 }
459
Winson8aa99592016-01-19 15:07:07 -0800460 /**
461 * Called to update the dismiss animation.
462 */
463 protected void prepareDismissAnimation(View view, Animator anim) {
464 // Do nothing
465 }
466
Mady Mellor4b80b102016-01-22 08:03:58 -0800467 public void snapChild(final View animView, final float targetLeft, float velocity) {
468 final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
469 AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
Mady Mellor43c2cd12016-12-12 21:05:13 -0800470 @Override
Mady Mellor4b80b102016-01-22 08:03:58 -0800471 public void onAnimationUpdate(ValueAnimator animation) {
472 onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
473 }
474 };
475
476 Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
Mady Mellor34958fa2016-02-23 09:52:17 -0800477 if (anim == null) {
478 return;
479 }
Michael Jurka67b03702013-02-15 17:35:48 +0100480 anim.addListener(new AnimatorListenerAdapter() {
Mady Mellor7a5b2b62017-04-14 18:53:45 -0700481 boolean wasCancelled = false;
482
483 @Override
484 public void onAnimationCancel(Animator animator) {
485 wasCancelled = true;
486 }
487
Mady Mellor43c2cd12016-12-12 21:05:13 -0800488 @Override
Michael Jurka67b03702013-02-15 17:35:48 +0100489 public void onAnimationEnd(Animator animator) {
dongwan0605.kim30637e42016-03-02 17:16:47 +0900490 mSnappingChild = false;
Mady Mellor7a5b2b62017-04-14 18:53:45 -0700491 if (!wasCancelled) {
492 updateSwipeProgressFromOffset(animView, canBeDismissed);
Evan Lairde55c6012019-03-13 12:54:37 -0400493 onChildSnappedBack(animView, targetLeft);
Mady Mellor7a5b2b62017-04-14 18:53:45 -0700494 mCallback.onChildSnappedBack(animView, targetLeft);
495 }
Michael Jurka07d40462011-07-19 10:54:38 -0700496 }
497 });
Winson8aa99592016-01-19 15:07:07 -0800498 prepareSnapBackAnimation(animView, anim);
dongwan0605.kim30637e42016-03-02 17:16:47 +0900499 mSnappingChild = true;
Mady Mellor8bdeca02019-02-20 18:34:24 -0800500 float maxDistance = Math.abs(targetLeft - getTranslation(animView));
501 mFlingAnimationUtils.apply(anim, getTranslation(animView), targetLeft, velocity,
502 maxDistance);
Michael Jurka07d40462011-07-19 10:54:38 -0700503 anim.start();
504 }
505
Winsonc5fd3502016-01-18 15:18:37 -0800506 /**
Evan Lairde55c6012019-03-13 12:54:37 -0400507 * Give the swipe helper itself a chance to do something on snap back so NSSL doesn't have
508 * to tell us what to do
509 */
510 protected void onChildSnappedBack(View animView, float targetLeft) {
511 }
512
513 /**
Winsonc5fd3502016-01-18 15:18:37 -0800514 * Called to update the snap back animation.
515 */
Winson8aa99592016-01-19 15:07:07 -0800516 protected void prepareSnapBackAnimation(View view, Animator anim) {
Winsonc5fd3502016-01-18 15:18:37 -0800517 // Do nothing
518 }
519
Mady Mellor4b80b102016-01-22 08:03:58 -0800520 /**
521 * Called when there's a down event.
522 */
Mady Mellor95d743c2017-01-10 12:05:27 -0800523 public void onDownUpdate(View currView, MotionEvent ev) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800524 // Do nothing
525 }
526
527 /**
528 * Called on a move event.
529 */
Mady Mellor95d743c2017-01-10 12:05:27 -0800530 protected void onMoveUpdate(View view, MotionEvent ev, float totalTranslation, float delta) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800531 // Do nothing
532 }
533
534 /**
535 * Called in {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)} when the current
536 * view is being animated to dismiss or snap.
537 */
538 public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
Winsonbde852d2016-04-15 19:06:54 -0700539 updateSwipeProgressFromOffset(animView, canBeDismissed, value);
Mady Mellor4b80b102016-01-22 08:03:58 -0800540 }
541
dongwan0605.kim30637e42016-03-02 17:16:47 +0900542 private void snapChildInstantly(final View view) {
543 final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
544 setTranslation(view, 0);
545 updateSwipeProgressFromOffset(view, canAnimViewBeDismissed);
546 }
547
Mady Mellor86889c22016-04-18 16:37:06 -0700548 /**
549 * Called when a view is updated to be non-dismissable, if the view was being dismissed before
550 * the update this will handle snapping it back into place.
551 *
552 * @param view the view to snap if necessary.
553 * @param animate whether to animate the snap or not.
554 * @param targetLeft the target to snap to.
555 */
556 public void snapChildIfNeeded(final View view, boolean animate, float targetLeft) {
dongwan0605.kim30637e42016-03-02 17:16:47 +0900557 if ((mDragging && mCurrView == view) || mSnappingChild) {
558 return;
559 }
560 boolean needToSnap = false;
561 Animator dismissPendingAnim = mDismissPendingMap.get(view);
562 if (dismissPendingAnim != null) {
563 needToSnap = true;
564 dismissPendingAnim.cancel();
565 } else if (getTranslation(view) != 0) {
566 needToSnap = true;
567 }
568 if (needToSnap) {
569 if (animate) {
Mady Mellor86889c22016-04-18 16:37:06 -0700570 snapChild(view, targetLeft, 0.0f /* velocity */);
dongwan0605.kim30637e42016-03-02 17:16:47 +0900571 } else {
572 snapChildInstantly(view);
573 }
574 }
575 }
576
Mady Mellor43c2cd12016-12-12 21:05:13 -0800577 @Override
Michael Jurka07d40462011-07-19 10:54:38 -0700578 public boolean onTouchEvent(MotionEvent ev) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700579 if (mLongPressSent && !mMenuRowIntercepting) {
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400580 return true;
581 }
582
Mady Mellor4ab28202017-06-06 11:42:50 -0700583 if (!mDragging && !mMenuRowIntercepting) {
Jorim Jaggi28f0e592014-08-05 22:03:07 +0200584 if (mCallback.getChildAtPosition(ev) != null) {
585
586 // We are dragging directly over a card, make sure that we also catch the gesture
587 // even if nobody else wants the touch event.
588 onInterceptTouchEvent(ev);
589 return true;
590 } else {
591
592 // We are not doing anything, make sure the long press callback
593 // is not still ticking like a bomb waiting to go off.
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000594 cancelLongPress();
Jorim Jaggi28f0e592014-08-05 22:03:07 +0200595 return false;
596 }
Michael Jurka07d40462011-07-19 10:54:38 -0700597 }
598
599 mVelocityTracker.addMovement(ev);
600 final int action = ev.getAction();
601 switch (action) {
602 case MotionEvent.ACTION_OUTSIDE:
603 case MotionEvent.ACTION_MOVE:
604 if (mCurrView != null) {
605 float delta = getPos(ev) - mInitialTouchPos;
Selim Cinek19c8c702014-08-25 22:09:19 +0200606 float absDelta = Math.abs(delta);
Selim Cinek34cf5c42014-09-26 15:39:00 +0200607 if (absDelta >= getFalsingThreshold()) {
Selim Cinek19c8c702014-08-25 22:09:19 +0200608 mTouchAboveFalsingThreshold = true;
609 }
Michael Jurka07d40462011-07-19 10:54:38 -0700610 // don't let items that can't be dismissed be dragged more than
611 // maxScrollDistance
Gus Prevas37d67e22018-11-02 14:48:55 -0400612 if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissedInDirection(mCurrView,
613 delta > 0)) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800614 float size = getSize(mCurrView);
Mady Mellor55744252017-04-10 10:05:17 -0700615 float maxScrollDistance = MAX_SCROLL_SIZE_FRACTION * size;
Selim Cinek19c8c702014-08-25 22:09:19 +0200616 if (absDelta >= size) {
Michael Jurka07d40462011-07-19 10:54:38 -0700617 delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
618 } else {
Gus Prevasc4e68d42019-01-17 15:45:21 -0500619 int startPosition = mCallback.getConstrainSwipeStartPosition();
620 if (absDelta > startPosition) {
621 int signedStartPosition =
622 (int) (startPosition * Math.signum(delta));
623 delta = signedStartPosition
624 + maxScrollDistance * (float) Math.sin(
625 ((delta - signedStartPosition) / size) * (Math.PI / 2));
626 }
Michael Jurka07d40462011-07-19 10:54:38 -0700627 }
628 }
Michael Jurka67b03702013-02-15 17:35:48 +0100629
Mady Mellor4b80b102016-01-22 08:03:58 -0800630 setTranslation(mCurrView, mTranslation + delta);
631 updateSwipeProgressFromOffset(mCurrView, mCanCurrViewBeDimissed);
Mady Mellor95d743c2017-01-10 12:05:27 -0800632 onMoveUpdate(mCurrView, ev, mTranslation + delta, delta);
Michael Jurka07d40462011-07-19 10:54:38 -0700633 }
634 break;
635 case MotionEvent.ACTION_UP:
636 case MotionEvent.ACTION_CANCEL:
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000637 if (mCurrView == null) {
638 break;
639 }
640 mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, getMaxVelocity());
641 float velocity = getVelocity(mVelocityTracker);
Michael Jurka07d40462011-07-19 10:54:38 -0700642
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000643 if (!handleUpEvent(ev, mCurrView, velocity, getTranslation(mCurrView))) {
644 if (isDismissGesture(ev)) {
Michael Jurka07d40462011-07-19 10:54:38 -0700645 // flingadingy
Mady Mellordc6c97d2016-03-31 14:18:35 -0700646 dismissChild(mCurrView, velocity,
647 !swipedFastEnough() /* useAccelerateInterpolator */);
Michael Jurka07d40462011-07-19 10:54:38 -0700648 } else {
649 // snappity
Peter Ng622a9762011-08-29 10:56:53 -0700650 mCallback.onDragCancelled(mCurrView);
Mady Mellor4b80b102016-01-22 08:03:58 -0800651 snapChild(mCurrView, 0 /* leftTarget */, velocity);
Michael Jurka07d40462011-07-19 10:54:38 -0700652 }
dongwan0605.kim30637e42016-03-02 17:16:47 +0900653 mCurrView = null;
Michael Jurka07d40462011-07-19 10:54:38 -0700654 }
dongwan0605.kim30637e42016-03-02 17:16:47 +0900655 mDragging = false;
Michael Jurka07d40462011-07-19 10:54:38 -0700656 break;
657 }
658 return true;
659 }
660
Selim Cinek34cf5c42014-09-26 15:39:00 +0200661 private int getFalsingThreshold() {
662 float factor = mCallback.getFalsingThresholdFactor();
663 return (int) (mFalsingThreshold * factor);
664 }
665
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000666 private float getMaxVelocity() {
667 return MAX_DISMISS_VELOCITY * mDensityScale;
668 }
669
670 protected float getEscapeVelocity() {
Winsonbde852d2016-04-15 19:06:54 -0700671 return getUnscaledEscapeVelocity() * mDensityScale;
672 }
673
674 protected float getUnscaledEscapeVelocity() {
675 return SWIPE_ESCAPE_VELOCITY;
676 }
677
678 protected long getMaxEscapeAnimDuration() {
679 return MAX_ESCAPE_ANIMATION_DURATION;
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000680 }
681
682 protected boolean swipedFarEnough() {
683 float translation = getTranslation(mCurrView);
Mady Mellor55744252017-04-10 10:05:17 -0700684 return DISMISS_IF_SWIPED_FAR_ENOUGH
685 && Math.abs(translation) > SWIPED_FAR_ENOUGH_SIZE_FRACTION * getSize(mCurrView);
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000686 }
687
Mady Mellor95d743c2017-01-10 12:05:27 -0800688 public boolean isDismissGesture(MotionEvent ev) {
Gus Prevas37d67e22018-11-02 14:48:55 -0400689 float translation = getTranslation(mCurrView);
Mady Mellorbd707492017-05-10 17:51:25 -0700690 return ev.getActionMasked() == MotionEvent.ACTION_UP
Dave Mankoffc88d6222018-10-25 15:31:20 -0400691 && !mFalsingManager.isUnlockingDisabled()
Mady Mellorbd707492017-05-10 17:51:25 -0700692 && !isFalseGesture(ev) && (swipedFastEnough() || swipedFarEnough())
Gus Prevas37d67e22018-11-02 14:48:55 -0400693 && mCallback.canChildBeDismissedInDirection(mCurrView, translation > 0);
Mady Mellorbd707492017-05-10 17:51:25 -0700694 }
695
696 public boolean isFalseGesture(MotionEvent ev) {
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000697 boolean falsingDetected = mCallback.isAntiFalsingNeeded();
698 if (mFalsingManager.isClassiferEnabled()) {
699 falsingDetected = falsingDetected && mFalsingManager.isFalseTouch();
700 } else {
701 falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold;
702 }
Mady Mellorbd707492017-05-10 17:51:25 -0700703 return falsingDetected;
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000704 }
705
706 protected boolean swipedFastEnough() {
707 float velocity = getVelocity(mVelocityTracker);
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000708 float translation = getTranslation(mCurrView);
Mady Mellordc6c97d2016-03-31 14:18:35 -0700709 boolean ret = (Math.abs(velocity) > getEscapeVelocity())
710 && (velocity > 0) == (translation > 0);
Mady Mellor3a5e8dd2016-03-12 00:13:23 +0000711 return ret;
712 }
713
714 protected boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
715 float translation) {
716 return false;
717 }
718
Michael Jurka07d40462011-07-19 10:54:38 -0700719 public interface Callback {
720 View getChildAtPosition(MotionEvent ev);
721
Michael Jurka07d40462011-07-19 10:54:38 -0700722 boolean canChildBeDismissed(View v);
723
Gus Prevas37d67e22018-11-02 14:48:55 -0400724 /**
725 * Returns true if the provided child can be dismissed by a swipe in the given direction.
726 *
727 * @param isRightOrDown {@code true} if the swipe direction is right or down,
728 * {@code false} if it is left or up.
729 */
730 default boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
731 return canChildBeDismissed(v);
732 }
733
Selim Cinek19c8c702014-08-25 22:09:19 +0200734 boolean isAntiFalsingNeeded();
735
Michael Jurka07d40462011-07-19 10:54:38 -0700736 void onBeginDrag(View v);
737
738 void onChildDismissed(View v);
Peter Ng622a9762011-08-29 10:56:53 -0700739
740 void onDragCancelled(View v);
Selim Cinekeb973562014-05-02 17:07:49 +0200741
Mady Mellor4b80b102016-01-22 08:03:58 -0800742 /**
743 * Called when the child is snapped to a position.
744 *
745 * @param animView the view that was snapped.
746 * @param targetLeft the left position the view was snapped to.
747 */
748 void onChildSnappedBack(View animView, float targetLeft);
Adrian Roos5d9cc662014-05-28 17:08:13 +0200749
750 /**
751 * Updates the swipe progress on a child.
752 *
753 * @return if true, prevents the default alpha fading.
754 */
755 boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress);
Selim Cinek34cf5c42014-09-26 15:39:00 +0200756
757 /**
758 * @return The factor the falsing threshold should be multiplied with
759 */
760 float getFalsingThresholdFactor();
yoshiki iguchi355692b2018-01-15 11:14:25 +0900761
762 /**
Gus Prevasc4e68d42019-01-17 15:45:21 -0500763 * @return The position, in pixels, at which a constrained swipe should start being
764 * constrained.
765 */
766 default int getConstrainSwipeStartPosition() {
767 return 0;
768 }
769
770 /**
yoshiki iguchi355692b2018-01-15 11:14:25 +0900771 * @return If true, the given view is draggable.
772 */
773 default boolean canChildBeDragged(@NonNull View animView) { return true; }
Michael Jurka07d40462011-07-19 10:54:38 -0700774 }
Michael Jurka07d40462011-07-19 10:54:38 -0700775}