1e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar/*
2e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
3e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar *
4e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * you may not use this file except in compliance with the License.
6e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * You may obtain a copy of the License at
7e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar *
8e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar *
10e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * See the License for the specific language governing permissions and
14e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * limitations under the License.
15e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar */
16e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
17e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarpackage android.support.v7.widget.helper;
18e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
19e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.graphics.Canvas;
20e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.graphics.Rect;
21e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.os.Build;
22e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v4.animation.ValueAnimatorCompat;
23e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v4.animation.AnimatorCompatHelper;
24e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v4.animation.AnimatorListenerCompat;
25e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v4.animation.AnimatorUpdateListenerCompat;
26e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v4.view.GestureDetectorCompat;
27e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v4.view.MotionEventCompat;
28e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v4.view.VelocityTrackerCompat;
29e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v4.view.ViewCompat;
30e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v7.widget.LinearLayoutManager;
31e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v7.widget.RecyclerView;
32e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.util.Log;
33e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.view.GestureDetector;
34e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.view.HapticFeedbackConstants;
35e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.view.MotionEvent;
36e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.view.VelocityTracker;
37e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.view.View;
38e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.view.ViewConfiguration;
39e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.view.ViewParent;
40e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v7.recyclerview.R;
41e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
42e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport java.util.ArrayList;
43e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport java.util.List;
44e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
45e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v7.widget.RecyclerView.OnItemTouchListener;
46e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v7.widget.RecyclerView.ViewHolder;
47e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.view.animation.Interpolator;
48e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
49e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar/**
50e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
51e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * <p>
52e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * It works with a RecyclerView and a Callback class, which configures what type of interactions
53e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * are enabled and also receives events when user performs these actions.
54e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * <p>
55e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * Depending on which functionality you support, you should override
56e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * {@link Callback#onMove(RecyclerView, ViewHolder, ViewHolder)} and / or
57e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * {@link Callback#onSwiped(ViewHolder, int)}.
58e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * <p>
59e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * This class is designed to work with any LayoutManager but for certain situations, it can be
60e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * optimized for your custom LayoutManager by extending methods in the
61e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * {@link ItemTouchHelper.Callback} class or implementing {@link ItemTouchHelper.ViewDropHandler}
62e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * interface in your LayoutManager.
63e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * <p>
64e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * By default, ItemTouchHelper moves the items' translateX/Y properties to reposition them. On
65e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * platforms older than Honeycomb, ItemTouchHelper uses canvas translations and View's visibility
66e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * property to move items in response to touch events. You can customize these behaviors by
67e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * overriding {@link Callback#onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int,
68e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * boolean)}
69e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * or {@link Callback#onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int,
70e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * boolean)}.
71e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * <p/>
72e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * Most of the time, you only need to override <code>onChildDraw</code> but due to limitations of
73e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * platform prior to Honeycomb, you may need to implement <code>onChildDrawOver</code> as well.
74e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar */
75e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarpublic class ItemTouchHelper extends RecyclerView.ItemDecoration
76e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        implements RecyclerView.OnChildAttachStateChangeListener {
77e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
78e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
79e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Up direction, used for swipe & drag control.
80e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
81e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int UP = 1;
82e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
83e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
84e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Down direction, used for swipe & drag control.
85e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
86e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int DOWN = 1 << 1;
87e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
88e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
89e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Left direction, used for swipe & drag control.
90e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
91e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int LEFT = 1 << 2;
92e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
93e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
94e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Right direction, used for swipe & drag control.
95e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
96e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int RIGHT = 1 << 3;
97e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
98e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    // If you change these relative direction values, update Callback#convertToAbsoluteDirection,
99e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    // Callback#convertToRelativeDirection.
100e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
101e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Horizontal start direction. Resolved to LEFT or RIGHT depending on RecyclerView's layout
102e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * direction. Used for swipe & drag control.
103e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
104e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int START = LEFT << 2;
105e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
106e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
107e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Horizontal end direction. Resolved to LEFT or RIGHT depending on RecyclerView's layout
108e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * direction. Used for swipe & drag control.
109e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
110e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int END = RIGHT << 2;
111e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
112e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
113e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * ItemTouchHelper is in idle state. At this state, either there is no related motion event by
114e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * the user or latest motion events have not yet triggered a swipe or drag.
115e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
116e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int ACTION_STATE_IDLE = 0;
117e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
118e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
119e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * A View is currently being swiped.
120e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
121e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int ACTION_STATE_SWIPE = 1;
122e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
123e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
124e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * A View is currently being dragged.
125e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
126e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int ACTION_STATE_DRAG = 2;
127e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
128e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
129e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Animation type for views which are swiped successfully.
130e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
131e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 1 << 1;
132e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
133e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
134e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Animation type for views which are not completely swiped thus will animate back to their
135e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * original position.
136e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
137e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int ANIMATION_TYPE_SWIPE_CANCEL = 1 << 2;
138e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
139e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
140e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Animation type for views that were dragged and now will animate to their final position.
141e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
142e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static final int ANIMATION_TYPE_DRAG = 1 << 3;
143e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
144e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static final String TAG = "ItemTouchHelper";
145e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
146e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static final boolean DEBUG = false;
147e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
148e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static final int ACTIVE_POINTER_ID_NONE = -1;
149e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
150e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static final int DIRECTION_FLAG_COUNT = 8;
151e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
152e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static final int ACTION_MODE_IDLE_MASK = (1 << DIRECTION_FLAG_COUNT) - 1;
153e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
154e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static final int ACTION_MODE_SWIPE_MASK = ACTION_MODE_IDLE_MASK << DIRECTION_FLAG_COUNT;
155e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
156e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static final int ACTION_MODE_DRAG_MASK = ACTION_MODE_SWIPE_MASK << DIRECTION_FLAG_COUNT;
157e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
158e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
159e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Views, whose state should be cleared after they are detached from RecyclerView.
160e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * This is necessary after swipe dismissing an item. We wait until animator finishes its job
161e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * to clean these views.
162e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
163e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    final List<View> mPendingCleanup = new ArrayList<View>();
164e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
165e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
166e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Re-use array to calculate dx dy for a ViewHolder
167e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
168e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private final float[] mTmpPosition = new float[2];
169e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
170e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
171e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Currently selected view holder
172e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
173e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    ViewHolder mSelected = null;
174e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
175e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
176e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * The reference coordinates for the action start. For drag & drop, this is the time long
177e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * press is completed vs for swipe, this is the initial touch point.
178e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
179e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    float mInitialTouchX;
180e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
181e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    float mInitialTouchY;
182e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
183e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
184e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * The diff between the last event and initial touch.
185e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
186e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    float mDx;
187e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
188e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    float mDy;
189e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
190e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
191e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * The coordinates of the selected view at the time it is selected. We record these values
192e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * when action starts so that we can consistently position it even if LayoutManager moves the
193e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * View.
194e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
195e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    float mSelectedStartX;
196e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
197e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    float mSelectedStartY;
198e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
199e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
200e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * The pointer we are tracking.
201e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
202e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    int mActivePointerId = ACTIVE_POINTER_ID_NONE;
203e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
204e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
205e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Developer callback which controls the behavior of ItemTouchHelper.
206e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
207e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    Callback mCallback;
208e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
209e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
210e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Current mode.
211e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
212e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    int mActionState = ACTION_STATE_IDLE;
213e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
214e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
215e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * The direction flags obtained from unmasking
216e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link Callback#getAbsoluteMovementFlags(RecyclerView, ViewHolder)} for the current
217e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * action state.
218e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
219e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    int mSelectedFlags;
220e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
221e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
222e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * When a View is dragged or swiped and needs to go back to where it was, we create a Recover
223e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Animation and animate it to its location using this custom Animator, instead of using
224e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * framework Animators.
225e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Using framework animators has the side effect of clashing with ItemAnimator, creating
226e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * jumpy UIs.
227e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
228e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    List<RecoverAnimation> mRecoverAnimations = new ArrayList<RecoverAnimation>();
229e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
230e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private int mSlop;
231e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
232e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private RecyclerView mRecyclerView;
233e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
234e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
235e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * When user drags a view to the edge, we start scrolling the LayoutManager as long as View
236e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * is partially out of bounds.
237e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
238e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private final Runnable mScrollRunnable = new Runnable() {
239e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
240e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void run() {
241e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mSelected != null && scrollIfNecessary()) {
242e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (mSelected != null) { //it might be lost during scrolling
243e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    moveIfNecessary(mSelected);
244e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
245e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mRecyclerView.removeCallbacks(mScrollRunnable);
246e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ViewCompat.postOnAnimation(mRecyclerView, this);
247e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
248e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
249e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    };
250e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
251e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
252e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Used for detecting fling swipe
253e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
254e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private VelocityTracker mVelocityTracker;
255e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
256e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    //re-used list for selecting a swap target
257e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private List<ViewHolder> mSwapTargets;
258e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
259e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    //re used for for sorting swap targets
260e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private List<Integer> mDistances;
261e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
262e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
263e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * If drag & drop is supported, we use child drawing order to bring them to front.
264e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
265e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private RecyclerView.ChildDrawingOrderCallback mChildDrawingOrderCallback = null;
266e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
267e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
268e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * This keeps a reference to the child dragged by the user. Even after user stops dragging,
269e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * until view reaches its final position (end of recover animation), we keep a reference so
270e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * that it can be drawn above other children.
271e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
272e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private View mOverdrawChild = null;
273e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
274e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
275e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * We cache the position of the overdraw child to avoid recalculating it each time child
276e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * position callback is called. This value is invalidated whenever a child is attached or
277e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * detached.
278e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
279e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private int mOverdrawChildPosition = -1;
280e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
281e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
282e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Used to detect long press.
283e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
284e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private GestureDetectorCompat mGestureDetector;
285e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
286e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private final OnItemTouchListener mOnItemTouchListener
287e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            = new OnItemTouchListener() {
288e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
289e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent event) {
290e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mGestureDetector.onTouchEvent(event);
291e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (DEBUG) {
292e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                Log.d(TAG, "intercept: x:" + event.getX() + ",y:" + event.getY() + ", " + event);
293e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
294e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int action = MotionEventCompat.getActionMasked(event);
295e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (action == MotionEvent.ACTION_DOWN) {
296e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mActivePointerId = MotionEventCompat.getPointerId(event, 0);
297e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mInitialTouchX = event.getX();
298e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mInitialTouchY = event.getY();
299e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                obtainVelocityTracker();
300e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (mSelected == null) {
301e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    final RecoverAnimation animation = findAnimation(event);
302e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (animation != null) {
303e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mInitialTouchX -= animation.mX;
304e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mInitialTouchY -= animation.mY;
305e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        endRecoverAnimation(animation.mViewHolder, true);
306e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (mPendingCleanup.remove(animation.mViewHolder.itemView)) {
307e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            mCallback.clearView(mRecyclerView, animation.mViewHolder);
308e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
309e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        select(animation.mViewHolder, animation.mActionState);
310e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        updateDxDy(event, mSelectedFlags, 0);
311e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
312e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
313e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
314e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mActivePointerId = ACTIVE_POINTER_ID_NONE;
315e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                select(null, ACTION_STATE_IDLE);
316e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else if (mActivePointerId != ACTIVE_POINTER_ID_NONE) {
317e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // in a non scroll orientation, if distance change is above threshold, we
318e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // can select the item
319e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int index = MotionEventCompat.findPointerIndex(event, mActivePointerId);
320e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (DEBUG) {
321e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    Log.d(TAG, "pointer index " + index);
322e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
323e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (index >= 0) {
324e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    checkSelectForSwipe(action, event, index);
325e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
326e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
327e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mVelocityTracker != null) {
328e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mVelocityTracker.addMovement(event);
329e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
330e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return mSelected != null;
331e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
332e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
333e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
334e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onTouchEvent(RecyclerView recyclerView, MotionEvent event) {
335e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mGestureDetector.onTouchEvent(event);
336e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (DEBUG) {
337e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                Log.d(TAG,
338e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        "on touch: x:" + mInitialTouchX + ",y:" + mInitialTouchY + ", :" + event);
339e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
340e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mVelocityTracker != null) {
341e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mVelocityTracker.addMovement(event);
342e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
343e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mActivePointerId == ACTIVE_POINTER_ID_NONE) {
344e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return;
345e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
346e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int action = MotionEventCompat.getActionMasked(event);
347e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int activePointerIndex = MotionEventCompat
348e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    .findPointerIndex(event, mActivePointerId);
349e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (activePointerIndex >= 0) {
350e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                checkSelectForSwipe(action, event, activePointerIndex);
351e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
352e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            ViewHolder viewHolder = mSelected;
353e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (viewHolder == null) {
354e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return;
355e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
356e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            switch (action) {
357e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                case MotionEvent.ACTION_MOVE: {
358e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    // Find the index of the active pointer and fetch its position
359e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (activePointerIndex >= 0) {
360e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        updateDxDy(event, mSelectedFlags, activePointerIndex);
361e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        moveIfNecessary(viewHolder);
362e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mRecyclerView.removeCallbacks(mScrollRunnable);
363e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mScrollRunnable.run();
364e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mRecyclerView.invalidate();
365e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
366e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    break;
367e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
368e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                case MotionEvent.ACTION_CANCEL:
369e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                case MotionEvent.ACTION_UP:
370e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (mVelocityTracker != null) {
371e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mVelocityTracker
372e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                                .computeCurrentVelocity(1000, mRecyclerView.getMaxFlingVelocity());
373e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
374e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    select(null, ACTION_STATE_IDLE);
375e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    mActivePointerId = ACTIVE_POINTER_ID_NONE;
376e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    break;
377e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                case MotionEvent.ACTION_POINTER_UP: {
378e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    final int pointerIndex = MotionEventCompat.getActionIndex(event);
379e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex);
380e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (pointerId == mActivePointerId) {
381e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (mVelocityTracker != null) {
382e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            mVelocityTracker
383e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                                    .computeCurrentVelocity(1000,
384e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                                            mRecyclerView.getMaxFlingVelocity());
385e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
386e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        // This was our active pointer going up. Choose a new
387e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        // active pointer and adjust accordingly.
388e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
389e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mActivePointerId = MotionEventCompat.getPointerId(event, newPointerIndex);
390e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        updateDxDy(event, mSelectedFlags, pointerIndex);
391e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
392e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    break;
393e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
394e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
395e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
396e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
397e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
398e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
399e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (!disallowIntercept) {
400e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return;
401e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
402e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            select(null, ACTION_STATE_IDLE);
403e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
404e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    };
405e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
406e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
407e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Temporary rect instance that is used when we need to lookup Item decorations.
408e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
409e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private Rect mTmpRect;
410e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
411e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
412e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * When user started to drag scroll. Reset when we don't scroll
413e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
414e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private long mDragScrollStartTimeInMs;
415e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
416e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
417e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Creates an ItemTouchHelper that will work with the given Callback.
418e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <p>
419e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * You can attach ItemTouchHelper to a RecyclerView via
420e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link #attachToRecyclerView(RecyclerView)}. Upon attaching, it will add an item decoration,
421e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * an onItemTouchListener and a Child attach / detach listener to the RecyclerView.
422e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *
423e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * @param callback The Callback which controls the behavior of this touch helper.
424e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
425e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public ItemTouchHelper(Callback callback) {
426e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mCallback = callback;
427e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
428e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
429e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static boolean hitTest(View child, float x, float y, float left, float top) {
430e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return x >= left &&
431e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                x <= left + child.getWidth() &&
432e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                y >= top &&
433e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                y <= top + child.getHeight();
434e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
435e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
436e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
437e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Attaches the ItemTouchHelper to the provided RecyclerView. If TouchHelper is already
438e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * attached
439e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * to a RecyclerView, it will first detach from the previous one.
440e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *
441e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * @param recyclerView The RecyclerView instance to which you want to add this helper.
442e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
443e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public void attachToRecyclerView(RecyclerView recyclerView) {
444e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mRecyclerView == recyclerView) {
445e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return; // nothing to do
446e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
447e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mRecyclerView != null) {
448e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            destroyCallbacks();
449e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
450e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecyclerView = recyclerView;
451e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mRecyclerView != null) {
452e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            setupCallbacks();
453e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
454e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
455e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
456e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void setupCallbacks() {
457e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        ViewConfiguration vc = ViewConfiguration.get(mRecyclerView.getContext());
458e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mSlop = vc.getScaledTouchSlop();
459e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecyclerView.addItemDecoration(this);
460e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecyclerView.addOnItemTouchListener(mOnItemTouchListener);
461e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecyclerView.addOnChildAttachStateChangeListener(this);
462e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        initGestureDetector();
463e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
464e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
465e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void destroyCallbacks() {
466e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecyclerView.removeItemDecoration(this);
467e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecyclerView.removeOnItemTouchListener(mOnItemTouchListener);
468e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecyclerView.removeOnChildAttachStateChangeListener(this);
469e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // clean all attached
470e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int recoverAnimSize = mRecoverAnimations.size();
471e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        for (int i = recoverAnimSize - 1; i >= 0; i--) {
472e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final RecoverAnimation recoverAnimation = mRecoverAnimations.get(0);
473e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mCallback.clearView(mRecyclerView, recoverAnimation.mViewHolder);
474e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
475e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecoverAnimations.clear();
476e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mOverdrawChild = null;
477e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mOverdrawChildPosition = -1;
478e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        releaseVelocityTracker();
479e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
480e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
481e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void initGestureDetector() {
482e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mGestureDetector != null) {
483e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
484e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
485e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mGestureDetector = new GestureDetectorCompat(mRecyclerView.getContext(),
486e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                new ItemTouchHelperGestureListener());
487e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
488e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
489e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void getSelectedDxDy(float[] outPosition) {
490e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if ((mSelectedFlags & (LEFT | RIGHT)) != 0) {
491e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            outPosition[0] = mSelectedStartX + mDx - mSelected.itemView.getLeft();
492e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        } else {
493e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            outPosition[0] = ViewCompat.getTranslationX(mSelected.itemView);
494e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
495e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if ((mSelectedFlags & (UP | DOWN)) != 0) {
496e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            outPosition[1] = mSelectedStartY + mDy - mSelected.itemView.getTop();
497e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        } else {
498e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            outPosition[1] = ViewCompat.getTranslationY(mSelected.itemView);
499e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
500e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
501e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
502e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    @Override
503e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
504e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        float dx = 0, dy = 0;
505e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mSelected != null) {
506e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            getSelectedDxDy(mTmpPosition);
507e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            dx = mTmpPosition[0];
508e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            dy = mTmpPosition[1];
509e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
510e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mCallback.onDrawOver(c, parent, mSelected,
511e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mRecoverAnimations, mActionState, dx, dy);
512e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
513e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
514e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    @Override
515e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
516e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // we don't know if RV changed something so we should invalidate this index.
517e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mOverdrawChildPosition = -1;
518e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        float dx = 0, dy = 0;
519e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mSelected != null) {
520e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            getSelectedDxDy(mTmpPosition);
521e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            dx = mTmpPosition[0];
522e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            dy = mTmpPosition[1];
523e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
524e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mCallback.onDraw(c, parent, mSelected,
525e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mRecoverAnimations, mActionState, dx, dy);
526e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
527e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
528e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
529e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Starts dragging or swiping the given View. Call with null if you want to clear it.
530e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *
531e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * @param selected    The ViewHolder to drag or swipe. Can be null if you want to cancel the
532e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *                    current action
533e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * @param actionState The type of action
534e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
535e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void select(ViewHolder selected, int actionState) {
536e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (selected == mSelected && actionState == mActionState) {
537e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
538e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
539e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mDragScrollStartTimeInMs = Long.MIN_VALUE;
540e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int prevActionState = mActionState;
541e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // prevent duplicate animations
542e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        endRecoverAnimation(selected, true);
543e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mActionState = actionState;
544e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (actionState == ACTION_STATE_DRAG) {
545e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            // we remove after animation is complete. this means we only elevate the last drag
546e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            // child but that should perform good enough as it is very hard to start dragging a
547e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            // new child before the previous one settles.
548e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mOverdrawChild = selected.itemView;
549e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            addChildDrawingOrderCallback();
550e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
551e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        int actionStateMask = (1 << (DIRECTION_FLAG_COUNT + DIRECTION_FLAG_COUNT * actionState))
552e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                - 1;
553e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        boolean preventLayout = false;
554e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
555e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mSelected != null) {
556e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final ViewHolder prevSelected = mSelected;
557e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (prevSelected.itemView.getParent() != null) {
558e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int swipeDir = prevActionState == ACTION_STATE_DRAG ? 0
559e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        : swipeIfNecessary(prevSelected);
560e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                releaseVelocityTracker();
561e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // find where we should animate to
562e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final float targetTranslateX, targetTranslateY;
563e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                int animationType;
564e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                switch (swipeDir) {
565e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    case LEFT:
566e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    case RIGHT:
567e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    case START:
568e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    case END:
569e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        targetTranslateY = 0;
570e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        targetTranslateX = Math.signum(mDx) * mRecyclerView.getWidth();
571e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        break;
572e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    case UP:
573e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    case DOWN:
574e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        targetTranslateX = 0;
575e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        targetTranslateY = Math.signum(mDy) * mRecyclerView.getHeight();
576e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        break;
577e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    default:
578e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        targetTranslateX = 0;
579e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        targetTranslateY = 0;
580e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
581e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (prevActionState == ACTION_STATE_DRAG) {
582e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    animationType = ANIMATION_TYPE_DRAG;
583e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                } else if (swipeDir > 0) {
584e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    animationType = ANIMATION_TYPE_SWIPE_SUCCESS;
585e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                } else {
586e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    animationType = ANIMATION_TYPE_SWIPE_CANCEL;
587e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
588e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                getSelectedDxDy(mTmpPosition);
589e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final float currentTranslateX = mTmpPosition[0];
590e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final float currentTranslateY = mTmpPosition[1];
591e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final RecoverAnimation rv = new RecoverAnimation(prevSelected, animationType,
592e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        prevActionState, currentTranslateX, currentTranslateY,
593e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        targetTranslateX, targetTranslateY) {
594e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    @Override
595e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    public void onAnimationEnd(ValueAnimatorCompat animation) {
596e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        super.onAnimationEnd(animation);
597e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (this.mOverridden) {
598e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            return;
599e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
600e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (swipeDir <= 0) {
601e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            // this is a drag or failed swipe. recover immediately
602e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            mCallback.clearView(mRecyclerView, prevSelected);
603e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            // full cleanup will happen on onDrawOver
604e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        } else {
605e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            // wait until remove animation is complete.
606e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            mPendingCleanup.add(prevSelected.itemView);
607e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            mIsPendingCleanup = true;
608e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            if (swipeDir > 0) {
609e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                                // Animation might be ended by other animators during a layout.
610e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                                // We defer callback to avoid editing adapter during a layout.
611e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                                postDispatchSwipe(this, swipeDir);
612e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            }
613e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
614e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        // removed from the list after it is drawn for the last time
615e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (mOverdrawChild == prevSelected.itemView) {
616e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            removeChildDrawingOrderCallbackIfNecessary(prevSelected.itemView);
617e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
618e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
619e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                };
620e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final long duration = mCallback.getAnimationDuration(mRecyclerView, animationType,
621e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        targetTranslateX - currentTranslateX, targetTranslateY - currentTranslateY);
622e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                rv.setDuration(duration);
623e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mRecoverAnimations.add(rv);
624e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                rv.start();
625e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                preventLayout = true;
626e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else {
627e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                removeChildDrawingOrderCallbackIfNecessary(prevSelected.itemView);
628e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mCallback.clearView(mRecyclerView, prevSelected);
629e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
630e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mSelected = null;
631e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
632e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (selected != null) {
633e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mSelectedFlags =
634e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    (mCallback.getAbsoluteMovementFlags(mRecyclerView, selected) & actionStateMask)
635e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            >> (mActionState * DIRECTION_FLAG_COUNT);
636e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mSelectedStartX = selected.itemView.getLeft();
637e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mSelectedStartY = selected.itemView.getTop();
638e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mSelected = selected;
639e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
640e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (actionState == ACTION_STATE_DRAG) {
641e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mSelected.itemView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
642e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
643e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
644e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final ViewParent rvParent = mRecyclerView.getParent();
645e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (rvParent != null) {
646e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            rvParent.requestDisallowInterceptTouchEvent(mSelected != null);
647e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
648e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (!preventLayout) {
649e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mRecyclerView.getLayoutManager().requestSimpleAnimationsInNextLayout();
650e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
651e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mCallback.onSelectedChanged(mSelected, mActionState);
652e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecyclerView.invalidate();
653e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
654e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
655e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void postDispatchSwipe(final RecoverAnimation anim, final int swipeDir) {
656e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // wait until animations are complete.
657e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecyclerView.post(new Runnable() {
658e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            @Override
659e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            public void run() {
660e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (mRecyclerView != null && mRecyclerView.isAttachedToWindow() &&
661e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        !anim.mOverridden &&
662e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        anim.mViewHolder.getAdapterPosition() != RecyclerView.NO_POSITION) {
663e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    final RecyclerView.ItemAnimator animator = mRecyclerView.getItemAnimator();
664e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    // if animator is running or we have other active recover animations, we try
665e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    // not to call onSwiped because DefaultItemAnimator is not good at merging
666e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    // animations. Instead, we wait and batch.
667e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if ((animator == null || !animator.isRunning(null))
668e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            && !hasRunningRecoverAnim()) {
669e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mCallback.onSwiped(anim.mViewHolder, swipeDir);
670e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    } else {
671e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mRecyclerView.post(this);
672e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
673e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
674e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
675e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        });
676e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
677e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
678e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private boolean hasRunningRecoverAnim() {
679e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int size = mRecoverAnimations.size();
680e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        for (int i = 0; i < size; i++) {
681e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (!mRecoverAnimations.get(i).mEnded) {
682e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return true;
683e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
684e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
685e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return false;
686e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
687e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
688e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
689e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * If user drags the view to the edge, trigger a scroll if necessary.
690e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
691e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private boolean scrollIfNecessary() {
692e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mSelected == null) {
693e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDragScrollStartTimeInMs = Long.MIN_VALUE;
694e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return false;
695e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
696e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final long now = System.currentTimeMillis();
697e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final long scrollDuration = mDragScrollStartTimeInMs
698e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                == Long.MIN_VALUE ? 0 : now - mDragScrollStartTimeInMs;
699e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
700e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mTmpRect == null) {
701e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mTmpRect = new Rect();
702e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
703e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        int scrollX = 0;
704e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        int scrollY = 0;
705e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        lm.calculateItemDecorationsForChild(mSelected.itemView, mTmpRect);
706e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (lm.canScrollHorizontally()) {
707e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            int curX = (int) (mSelectedStartX + mDx);
708e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int leftDiff = curX - mTmpRect.left - mRecyclerView.getPaddingLeft();
709e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mDx < 0 && leftDiff < 0) {
710e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                scrollX = leftDiff;
711e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else if (mDx > 0) {
712e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int rightDiff =
713e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        curX + mSelected.itemView.getWidth() + mTmpRect.right
714e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                                - (mRecyclerView.getWidth() - mRecyclerView.getPaddingRight());
715e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (rightDiff > 0) {
716e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    scrollX = rightDiff;
717e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
718e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
719e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
720e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (lm.canScrollVertically()) {
721e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            int curY = (int) (mSelectedStartY + mDy);
722e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int topDiff = curY - mTmpRect.top - mRecyclerView.getPaddingTop();
723e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mDy < 0 && topDiff < 0) {
724e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                scrollY = topDiff;
725e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else if (mDy > 0) {
726e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int bottomDiff = curY + mSelected.itemView.getHeight() + mTmpRect.bottom -
727e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        (mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom());
728e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (bottomDiff > 0) {
729e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    scrollY = bottomDiff;
730e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
731e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
732e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
733e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (scrollX != 0) {
734e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            scrollX = mCallback.interpolateOutOfBoundsScroll(mRecyclerView,
735e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    mSelected.itemView.getWidth(), scrollX,
736e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    mRecyclerView.getWidth(), scrollDuration);
737e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
738e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (scrollY != 0) {
739e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            scrollY = mCallback.interpolateOutOfBoundsScroll(mRecyclerView,
740e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    mSelected.itemView.getHeight(), scrollY,
741e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    mRecyclerView.getHeight(), scrollDuration);
742e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
743e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (scrollX != 0 || scrollY != 0) {
744e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mDragScrollStartTimeInMs == Long.MIN_VALUE) {
745e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mDragScrollStartTimeInMs = now;
746e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
747e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mRecyclerView.scrollBy(scrollX, scrollY);
748e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return true;
749e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
750e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mDragScrollStartTimeInMs = Long.MIN_VALUE;
751e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return false;
752e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
753e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
754e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private List<ViewHolder> findSwapTargets(ViewHolder viewHolder) {
755e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mSwapTargets == null) {
756e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mSwapTargets = new ArrayList<ViewHolder>();
757e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDistances = new ArrayList<Integer>();
758e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        } else {
759e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mSwapTargets.clear();
760e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDistances.clear();
761e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
762e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int margin = mCallback.getBoundingBoxMargin();
763e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int left = Math.round(mSelectedStartX + mDx) - margin;
764e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int top = Math.round(mSelectedStartY + mDy) - margin;
765e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int right = left + viewHolder.itemView.getWidth() + 2 * margin;
766e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int bottom = top + viewHolder.itemView.getHeight() + 2 * margin;
767e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int centerX = (left + right) / 2;
768e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int centerY = (top + bottom) / 2;
769e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
770e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int childCount = lm.getChildCount();
771e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        for (int i = 0; i < childCount; i++) {
772e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            View other = lm.getChildAt(i);
773e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (other == viewHolder.itemView) {
774e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                continue;//myself!
775e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
776e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (other.getBottom() < top || other.getTop() > bottom
777e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    || other.getRight() < left || other.getLeft() > right) {
778e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                continue;
779e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
780e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final ViewHolder otherVh = mRecyclerView.getChildViewHolder(other);
781e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mCallback.canDropOver(mRecyclerView, mSelected, otherVh)) {
782e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // find the index to add
783e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int dx = Math.abs(centerX - (other.getLeft() + other.getRight()) / 2);
784e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int dy = Math.abs(centerY - (other.getTop() + other.getBottom()) / 2);
785e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int dist = dx * dx + dy * dy;
786e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
787e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                int pos = 0;
788e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int cnt = mSwapTargets.size();
789e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                for (int j = 0; j < cnt; j++) {
790e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (dist > mDistances.get(j)) {
791e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        pos++;
792e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    } else {
793e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        break;
794e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
795e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
796e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mSwapTargets.add(pos, otherVh);
797e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mDistances.add(pos, dist);
798e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
799e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
800e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return mSwapTargets;
801e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
802e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
803e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
804e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Checks if we should swap w/ another view holder.
805e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
806e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void moveIfNecessary(ViewHolder viewHolder) {
807e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mRecyclerView.isLayoutRequested()) {
808e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
809e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
810e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mActionState != ACTION_STATE_DRAG) {
811e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
812e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
813e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
814e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float threshold = mCallback.getMoveThreshold(viewHolder);
815e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int x = (int) (mSelectedStartX + mDx);
816e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int y = (int) (mSelectedStartY + mDy);
817e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (Math.abs(y - viewHolder.itemView.getTop()) < viewHolder.itemView.getHeight() * threshold
818e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                && Math.abs(x - viewHolder.itemView.getLeft())
819e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                < viewHolder.itemView.getWidth() * threshold) {
820e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
821e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
822e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        List<ViewHolder> swapTargets = findSwapTargets(viewHolder);
823e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (swapTargets.size() == 0) {
824e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
825e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
826e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // may swap.
827e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        ViewHolder target = mCallback.chooseDropTarget(viewHolder, swapTargets, x, y);
828e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (target == null) {
829e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mSwapTargets.clear();
830e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDistances.clear();
831e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
832e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
833e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int toPosition = target.getAdapterPosition();
834e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int fromPosition = viewHolder.getAdapterPosition();
835e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mCallback.onMove(mRecyclerView, viewHolder, target)) {
836e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            // keep target visible
837e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mCallback.onMoved(mRecyclerView, viewHolder, fromPosition,
838e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    target, toPosition, x, y);
839e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
840e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
841e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
842e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    @Override
843e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public void onChildViewAttachedToWindow(View view) {
844e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
845e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
846e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    @Override
847e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public void onChildViewDetachedFromWindow(View view) {
848e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        removeChildDrawingOrderCallbackIfNecessary(view);
849e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final ViewHolder holder = mRecyclerView.getChildViewHolder(view);
850e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (holder == null) {
851e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
852e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
853e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mSelected != null && holder == mSelected) {
854e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            select(null, ACTION_STATE_IDLE);
855e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        } else {
856e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            endRecoverAnimation(holder, false); // this may push it into pending cleanup list.
857e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mPendingCleanup.remove(holder.itemView)) {
858e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mCallback.clearView(mRecyclerView, holder);
859e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
860e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
861e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
862e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
863e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
864e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Returns the animation type or 0 if cannot be found.
865e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
866e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private int endRecoverAnimation(ViewHolder viewHolder, boolean override) {
867e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int recoverAnimSize = mRecoverAnimations.size();
868e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        for (int i = recoverAnimSize - 1; i >= 0; i--) {
869e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final RecoverAnimation anim = mRecoverAnimations.get(i);
870e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (anim.mViewHolder == viewHolder) {
871e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                anim.mOverridden |= override;
872e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (!anim.mEnded) {
873e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    anim.cancel();
874e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
875e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mRecoverAnimations.remove(i);
876e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                anim.mViewHolder.setIsRecyclable(true);
877e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return anim.mAnimationType;
878e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
879e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
880e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return 0;
881e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
882e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
883e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    @Override
884e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
885e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            RecyclerView.State state) {
886e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        outRect.setEmpty();
887e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
888e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
889e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void obtainVelocityTracker() {
890e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mVelocityTracker != null) {
891e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mVelocityTracker.recycle();
892e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
893e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mVelocityTracker = VelocityTracker.obtain();
894e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
895e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
896e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void releaseVelocityTracker() {
897e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mVelocityTracker != null) {
898e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mVelocityTracker.recycle();
899e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mVelocityTracker = null;
900e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
901e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
902e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
903e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private ViewHolder findSwipedView(MotionEvent motionEvent) {
904e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
905e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mActivePointerId == ACTIVE_POINTER_ID_NONE) {
906e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return null;
907e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
908e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int pointerIndex = MotionEventCompat.findPointerIndex(motionEvent, mActivePointerId);
909e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float dx = MotionEventCompat.getX(motionEvent, pointerIndex) - mInitialTouchX;
910e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float dy = MotionEventCompat.getY(motionEvent, pointerIndex) - mInitialTouchY;
911e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float absDx = Math.abs(dx);
912e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float absDy = Math.abs(dy);
913e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
914e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (absDx < mSlop && absDy < mSlop) {
915e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return null;
916e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
917e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (absDx > absDy && lm.canScrollHorizontally()) {
918e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return null;
919e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        } else if (absDy > absDx && lm.canScrollVertically()) {
920e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return null;
921e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
922e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        View child = findChildView(motionEvent);
923e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (child == null) {
924e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return null;
925e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
926e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return mRecyclerView.getChildViewHolder(child);
927e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
928e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
929e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
930e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Checks whether we should select a View for swiping.
931e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
932e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private boolean checkSelectForSwipe(int action, MotionEvent motionEvent, int pointerIndex) {
933e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mSelected != null || action != MotionEvent.ACTION_MOVE
934e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                || mActionState == ACTION_STATE_DRAG || !mCallback.isItemViewSwipeEnabled()) {
935e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return false;
936e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
937e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
938e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return false;
939e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
940e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final ViewHolder vh = findSwipedView(motionEvent);
941e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (vh == null) {
942e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return false;
943e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
944e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int movementFlags = mCallback.getAbsoluteMovementFlags(mRecyclerView, vh);
945e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
946e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int swipeFlags = (movementFlags & ACTION_MODE_SWIPE_MASK)
947e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                >> (DIRECTION_FLAG_COUNT * ACTION_STATE_SWIPE);
948e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
949e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (swipeFlags == 0) {
950e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return false;
951e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
952e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
953e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // mDx and mDy are only set in allowed directions. We use custom x/y here instead of
954e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // updateDxDy to avoid swiping if user moves more in the other direction
955e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float x = MotionEventCompat.getX(motionEvent, pointerIndex);
956e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float y = MotionEventCompat.getY(motionEvent, pointerIndex);
957e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
958e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // Calculate the distance moved
959e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float dx = x - mInitialTouchX;
960e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float dy = y - mInitialTouchY;
961e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // swipe target is chose w/o applying flags so it does not really check if swiping in that
962e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // direction is allowed. This why here, we use mDx mDy to check slope value again.
963e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float absDx = Math.abs(dx);
964e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float absDy = Math.abs(dy);
965e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
966e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (absDx < mSlop && absDy < mSlop) {
967e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return false;
968e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
969e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (absDx > absDy) {
970e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (dx < 0 && (swipeFlags & LEFT) == 0) {
971e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return false;
972e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
973e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (dx > 0 && (swipeFlags & RIGHT) == 0) {
974e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return false;
975e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
976e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        } else {
977e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (dy < 0 && (swipeFlags & UP) == 0) {
978e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return false;
979e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
980e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (dy > 0 && (swipeFlags & DOWN) == 0) {
981e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return false;
982e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
983e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
984e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mDx = mDy = 0f;
985e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mActivePointerId = MotionEventCompat.getPointerId(motionEvent, 0);
986e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        select(vh, ACTION_STATE_SWIPE);
987e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return true;
988e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
989e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
990e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private View findChildView(MotionEvent event) {
991e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // first check elevated views, if none, then call RV
992e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float x = event.getX();
993e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float y = event.getY();
994e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mSelected != null) {
995e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final View selectedView = mSelected.itemView;
996e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (hitTest(selectedView, x, y, mSelectedStartX + mDx, mSelectedStartY + mDy)) {
997e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return selectedView;
998e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
999e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1000e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) {
1001e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final RecoverAnimation anim = mRecoverAnimations.get(i);
1002e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final View view = anim.mViewHolder.itemView;
1003e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (hitTest(view, x, y, anim.mX, anim.mY)) {
1004e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return view;
1005e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1006e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1007e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return mRecyclerView.findChildViewUnder(x, y);
1008e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1009e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1010e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
1011e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Starts dragging the provided ViewHolder. By default, ItemTouchHelper starts a drag when a
1012e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * View is long pressed. You can disable that behavior via
1013e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link ItemTouchHelper.Callback#isLongPressDragEnabled()}.
1014e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <p>
1015e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * For this method to work:
1016e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <ul>
1017e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <li>The provided ViewHolder must be a child of the RecyclerView to which this
1018e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * ItemTouchHelper
1019e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * is attached.</li>
1020e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <li>{@link ItemTouchHelper.Callback} must have dragging enabled.</li>
1021e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <li>There must be a previous touch event that was reported to the ItemTouchHelper
1022e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * through RecyclerView's ItemTouchListener mechanism. As long as no other ItemTouchListener
1023e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * grabs previous events, this should work as expected.</li>
1024e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * </ul>
1025e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *
1026e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * For example, if you would like to let your user to be able to drag an Item by touching one
1027e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * of its descendants, you may implement it as follows:
1028e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <pre>
1029e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *     viewHolder.dragButton.setOnTouchListener(new View.OnTouchListener() {
1030e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *         public boolean onTouch(View v, MotionEvent event) {
1031e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
1032e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *                 mItemTouchHelper.startDrag(viewHolder);
1033e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             }
1034e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             return false;
1035e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *         }
1036e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *     });
1037e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * </pre>
1038e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <p>
1039e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *
1040e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * @param viewHolder The ViewHolder to start dragging. It must be a direct child of
1041e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *                   RecyclerView.
1042e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * @see ItemTouchHelper.Callback#isItemViewSwipeEnabled()
1043e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
1044e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public void startDrag(ViewHolder viewHolder) {
1045e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (!mCallback.hasDragFlag(mRecyclerView, viewHolder)) {
1046e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            Log.e(TAG, "Start drag has been called but swiping is not enabled");
1047e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
1048e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1049e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (viewHolder.itemView.getParent() != mRecyclerView) {
1050e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            Log.e(TAG, "Start drag has been called with a view holder which is not a child of "
1051e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    + "the RecyclerView which is controlled by this ItemTouchHelper.");
1052e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
1053e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1054e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        obtainVelocityTracker();
1055e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mDx = mDy = 0f;
1056e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        select(viewHolder, ACTION_STATE_DRAG);
1057e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1058e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1059e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
1060e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Starts swiping the provided ViewHolder. By default, ItemTouchHelper starts swiping a View
1061e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * when user swipes their finger (or mouse pointer) over the View. You can disable this
1062e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * behavior
1063e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * by overriding {@link ItemTouchHelper.Callback}
1064e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <p>
1065e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * For this method to work:
1066e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <ul>
1067e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <li>The provided ViewHolder must be a child of the RecyclerView to which this
1068e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * ItemTouchHelper is attached.</li>
1069e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <li>{@link ItemTouchHelper.Callback} must have swiping enabled.</li>
1070e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <li>There must be a previous touch event that was reported to the ItemTouchHelper
1071e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * through RecyclerView's ItemTouchListener mechanism. As long as no other ItemTouchListener
1072e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * grabs previous events, this should work as expected.</li>
1073e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * </ul>
1074e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *
1075e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * For example, if you would like to let your user to be able to swipe an Item by touching one
1076e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * of its descendants, you may implement it as follows:
1077e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <pre>
1078e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *     viewHolder.dragButton.setOnTouchListener(new View.OnTouchListener() {
1079e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *         public boolean onTouch(View v, MotionEvent event) {
1080e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
1081e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *                 mItemTouchHelper.startSwipe(viewHolder);
1082e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             }
1083e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             return false;
1084e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *         }
1085e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *     });
1086e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * </pre>
1087e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *
1088e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * @param viewHolder The ViewHolder to start swiping. It must be a direct child of
1089e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *                   RecyclerView.
1090e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
1091e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public void startSwipe(ViewHolder viewHolder) {
1092e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (!mCallback.hasSwipeFlag(mRecyclerView, viewHolder)) {
1093e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            Log.e(TAG, "Start swipe has been called but dragging is not enabled");
1094e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
1095e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1096e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (viewHolder.itemView.getParent() != mRecyclerView) {
1097e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            Log.e(TAG, "Start swipe has been called with a view holder which is not a child of "
1098e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    + "the RecyclerView controlled by this ItemTouchHelper.");
1099e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;
1100e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1101e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        obtainVelocityTracker();
1102e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mDx = mDy = 0f;
1103e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        select(viewHolder, ACTION_STATE_SWIPE);
1104e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1105e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1106e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private RecoverAnimation findAnimation(MotionEvent event) {
1107e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mRecoverAnimations.isEmpty()) {
1108e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return null;
1109e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1110e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        View target = findChildView(event);
1111e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) {
1112e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final RecoverAnimation anim = mRecoverAnimations.get(i);
1113e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (anim.mViewHolder.itemView == target) {
1114e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return anim;
1115e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1116e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1117e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return null;
1118e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1119e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1120e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void updateDxDy(MotionEvent ev, int directionFlags, int pointerIndex) {
1121e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float x = MotionEventCompat.getX(ev, pointerIndex);
1122e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float y = MotionEventCompat.getY(ev, pointerIndex);
1123e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1124e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // Calculate the distance moved
1125e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mDx = x - mInitialTouchX;
1126e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mDy = y - mInitialTouchY;
1127e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if ((directionFlags & LEFT) == 0) {
1128e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDx = Math.max(0, mDx);
1129e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1130e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if ((directionFlags & RIGHT) == 0) {
1131e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDx = Math.min(0, mDx);
1132e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1133e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if ((directionFlags & UP) == 0) {
1134e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDy = Math.max(0, mDy);
1135e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1136e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if ((directionFlags & DOWN) == 0) {
1137e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDy = Math.min(0, mDy);
1138e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1139e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1140e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1141e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private int swipeIfNecessary(ViewHolder viewHolder) {
1142e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mActionState == ACTION_STATE_DRAG) {
1143e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return 0;
1144e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1145e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int originalMovementFlags = mCallback.getMovementFlags(mRecyclerView, viewHolder);
1146e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int absoluteMovementFlags = mCallback.convertToAbsoluteDirection(
1147e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                originalMovementFlags,
1148e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ViewCompat.getLayoutDirection(mRecyclerView));
1149e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int flags = (absoluteMovementFlags
1150e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                & ACTION_MODE_SWIPE_MASK) >> (ACTION_STATE_SWIPE * DIRECTION_FLAG_COUNT);
1151e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (flags == 0) {
1152e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return 0;
1153e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1154e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int originalFlags = (originalMovementFlags
1155e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                & ACTION_MODE_SWIPE_MASK) >> (ACTION_STATE_SWIPE * DIRECTION_FLAG_COUNT);
1156e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        int swipeDir;
1157e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (Math.abs(mDx) > Math.abs(mDy)) {
1158e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if ((swipeDir = checkHorizontalSwipe(viewHolder, flags)) > 0) {
1159e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // if swipe dir is not in original flags, it should be the relative direction
1160e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if ((originalFlags & swipeDir) == 0) {
1161e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    // convert to relative
1162e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    return Callback.convertToRelativeDirection(swipeDir,
1163e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            ViewCompat.getLayoutDirection(mRecyclerView));
1164e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1165e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return swipeDir;
1166e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1167e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if ((swipeDir = checkVerticalSwipe(viewHolder, flags)) > 0) {
1168e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return swipeDir;
1169e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1170e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        } else {
1171e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if ((swipeDir = checkVerticalSwipe(viewHolder, flags)) > 0) {
1172e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return swipeDir;
1173e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1174e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if ((swipeDir = checkHorizontalSwipe(viewHolder, flags)) > 0) {
1175e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // if swipe dir is not in original flags, it should be the relative direction
1176e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if ((originalFlags & swipeDir) == 0) {
1177e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    // convert to relative
1178e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    return Callback.convertToRelativeDirection(swipeDir,
1179e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            ViewCompat.getLayoutDirection(mRecyclerView));
1180e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1181e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return swipeDir;
1182e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1183e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1184e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return 0;
1185e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1186e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1187e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private int checkHorizontalSwipe(ViewHolder viewHolder, int flags) {
1188e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if ((flags & (LEFT | RIGHT)) != 0) {
1189e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int dirFlag = mDx > 0 ? RIGHT : LEFT;
1190e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mVelocityTracker != null && mActivePointerId > -1) {
1191e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final float xVelocity = VelocityTrackerCompat
1192e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        .getXVelocity(mVelocityTracker, mActivePointerId);
1193e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int velDirFlag = xVelocity > 0f ? RIGHT : LEFT;
1194e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if ((velDirFlag & flags) != 0 && dirFlag == velDirFlag &&
1195e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        Math.abs(xVelocity) >= mRecyclerView.getMinFlingVelocity()) {
1196e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    return velDirFlag;
1197e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1198e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1199e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1200e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final float threshold = mRecyclerView.getWidth() * mCallback
1201e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    .getSwipeThreshold(viewHolder);
1202e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1203e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if ((flags & dirFlag) != 0 && Math.abs(mDx) > threshold) {
1204e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return dirFlag;
1205e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1206e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1207e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return 0;
1208e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1209e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1210e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private int checkVerticalSwipe(ViewHolder viewHolder, int flags) {
1211e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if ((flags & (UP | DOWN)) != 0) {
1212e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int dirFlag = mDy > 0 ? DOWN : UP;
1213e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mVelocityTracker != null && mActivePointerId > -1) {
1214e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final float yVelocity = VelocityTrackerCompat
1215e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        .getYVelocity(mVelocityTracker, mActivePointerId);
1216e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int velDirFlag = yVelocity > 0f ? DOWN : UP;
1217e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if ((velDirFlag & flags) != 0 && velDirFlag == dirFlag &&
1218e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        Math.abs(yVelocity) >= mRecyclerView.getMinFlingVelocity()) {
1219e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    return velDirFlag;
1220e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1221e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1222e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1223e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final float threshold = mRecyclerView.getHeight() * mCallback
1224e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    .getSwipeThreshold(viewHolder);
1225e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if ((flags & dirFlag) != 0 && Math.abs(mDy) > threshold) {
1226e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return dirFlag;
1227e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1228e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1229e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return 0;
1230e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1231e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1232e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void addChildDrawingOrderCallback() {
1233e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (Build.VERSION.SDK_INT >= 21) {
1234e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return;// we use elevation on Lollipop
1235e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1236e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mChildDrawingOrderCallback == null) {
1237e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mChildDrawingOrderCallback = new RecyclerView.ChildDrawingOrderCallback() {
1238e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                @Override
1239e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                public int onGetChildDrawingOrder(int childCount, int i) {
1240e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (mOverdrawChild == null) {
1241e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        return i;
1242e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
1243e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    int childPosition = mOverdrawChildPosition;
1244e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (childPosition == -1) {
1245e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        childPosition = mRecyclerView.indexOfChild(mOverdrawChild);
1246e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mOverdrawChildPosition = childPosition;
1247e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
1248e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (i == childCount - 1) {
1249e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        return childPosition;
1250e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
1251e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    return i < childPosition ? i : i + 1;
1252e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1253e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            };
1254e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1255e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mRecyclerView.setChildDrawingOrderCallback(mChildDrawingOrderCallback);
1256e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1257e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1258e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void removeChildDrawingOrderCallbackIfNecessary(View view) {
1259e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (view == mOverdrawChild) {
1260e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mOverdrawChild = null;
1261e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            // only remove if we've added
1262e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mChildDrawingOrderCallback != null) {
1263e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mRecyclerView.setChildDrawingOrderCallback(null);
1264e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1265e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1266e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1267e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1268e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
1269e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * An interface which can be implemented by LayoutManager for better integration with
1270e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link ItemTouchHelper}.
1271e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
1272e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public static interface ViewDropHandler {
1273e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1274e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1275e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called by the {@link ItemTouchHelper} after a View is dropped over another View.
1276e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1277e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * A LayoutManager should implement this interface to get ready for the upcoming move
1278e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * operation.
1279e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1280e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * For example, LinearLayoutManager sets up a "scrollToPositionWithOffset" calls so that
1281e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * the View under drag will be used as an anchor View while calculating the next layout,
1282e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * making layout stay consistent.
1283e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1284e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param view   The View which is being dragged. It is very likely that user is still
1285e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *               dragging this View so there might be other
1286e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *               {@link #prepareForDrop(View, View, int, int)} after this one.
1287e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param target The target view which is being dropped on.
1288e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param x      The <code>left</code> offset of the View that is being dragged. This value
1289e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *               includes the movement caused by the user.
1290e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param y      The <code>top</code> offset of the View that is being dragged. This value
1291e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *               includes the movement caused by the user.
1292e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1293e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void prepareForDrop(View view, View target, int x, int y);
1294e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
1295e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1296e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
1297e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * This class is the contract between ItemTouchHelper and your application. It lets you control
1298e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * which touch behaviors are enabled per each ViewHolder and also receive callbacks when user
1299e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * performs these actions.
1300e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <p>
1301e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * To control which actions user can take on each view, you should override
1302e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link #getMovementFlags(RecyclerView, ViewHolder)} and return appropriate set
1303e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * of direction flags. ({@link #LEFT}, {@link #RIGHT}, {@link #START}, {@link #END},
1304e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link #UP}, {@link #DOWN}). You can use
1305e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link #makeMovementFlags(int, int)} to easily construct it. Alternatively, you can use
1306e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link SimpleCallback}.
1307e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <p>
1308e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * If user drags an item, ItemTouchHelper will call
1309e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link Callback#onMove(RecyclerView, ViewHolder, ViewHolder)
1310e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * onMove(recyclerView, dragged, target)}.
1311e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * Upon receiving this callback, you should move the item from the old position
1312e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * ({@code dragged.getAdapterPosition()}) to new position ({@code target.getAdapterPosition()})
1313e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * in your adapter and also call {@link RecyclerView.Adapter#notifyItemMoved(int, int)}.
1314e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * To control where a View can be dropped, you can override
1315e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link #canDropOver(RecyclerView, ViewHolder, ViewHolder)}. When a
1316e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * dragging View overlaps multiple other views, Callback chooses the closest View with which
1317e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * dragged View might have changed positions. Although this approach works for many use cases,
1318e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * if you have a custom LayoutManager, you can override
1319e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link #chooseDropTarget(ViewHolder, java.util.List, int, int)} to select a
1320e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * custom drop target.
1321e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <p>
1322e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * When a View is swiped, ItemTouchHelper animates it until it goes out of bounds, then calls
1323e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * {@link #onSwiped(ViewHolder, int)}. At this point, you should update your
1324e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * adapter (e.g. remove the item) and call related Adapter#notify event.
1325e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
1326e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    @SuppressWarnings("UnusedParameters")
1327e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public abstract static class Callback {
1328e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1329e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200;
1330e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1331e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250;
1332e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1333e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        static final int RELATIVE_DIR_FLAGS = START | END |
1334e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ((START | END) << DIRECTION_FLAG_COUNT) |
1335e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ((START | END) << (2 * DIRECTION_FLAG_COUNT));
1336e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1337c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar        private static final ItemTouchUIUtil sUICallback;
1338e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1339e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private static final int ABS_HORIZONTAL_DIR_FLAGS = LEFT | RIGHT |
1340e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ((LEFT | RIGHT) << DIRECTION_FLAG_COUNT) |
1341e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ((LEFT | RIGHT) << (2 * DIRECTION_FLAG_COUNT));
1342e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1343e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private static final Interpolator sDragScrollInterpolator = new Interpolator() {
1344e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            public float getInterpolation(float t) {
1345e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return t * t * t * t * t;
1346e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1347e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        };
1348e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1349e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private static final Interpolator sDragViewScrollCapInterpolator = new Interpolator() {
1350e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            public float getInterpolation(float t) {
1351e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                t -= 1.0f;
1352e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return t * t * t * t * t + 1.0f;
1353e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1354e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        };
1355e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1356e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1357e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Drag scroll speed keeps accelerating until this many milliseconds before being capped.
1358e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1359e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private static final long DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS = 2000;
1360e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1361e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private int mCachedMaxScrollSpeed = -1;
1362e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1363e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        static {
1364e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (Build.VERSION.SDK_INT >= 21) {
1365c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar                sUICallback = new ItemTouchUIUtilImpl.Lollipop();
1366e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else if (Build.VERSION.SDK_INT >= 11) {
1367c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar                sUICallback = new ItemTouchUIUtilImpl.Honeycomb();
1368e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else {
1369c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar                sUICallback = new ItemTouchUIUtilImpl.Gingerbread();
1370e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1371e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1372e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1373e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1374c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * Returns the {@link ItemTouchUIUtil} that is used by the {@link Callback} class for visual
1375c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * changes on Views in response to user interactions. {@link ItemTouchUIUtil} has different
1376c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * implementations for different platform versions.
1377c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * <p>
1378c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * By default, {@link Callback} applies these changes on
1379c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * {@link RecyclerView.ViewHolder#itemView}.
1380c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * <p>
1381c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * For example, if you have a use case where you only want the text to move when user
1382c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * swipes over the view, you can do the following:
1383c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * <pre>
1384c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *     public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder){
1385c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *         getDefaultUIUtil().clearView(((ItemTouchViewHolder) viewHolder).textView);
1386c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *     }
1387c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *     public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
1388c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *         if (viewHolder != null){
1389c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *             getDefaultUIUtil().onSelected(((ItemTouchViewHolder) viewHolder).textView);
1390c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *         }
1391c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *     }
1392c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *     public void onChildDraw(Canvas c, RecyclerView recyclerView,
1393c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *             RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
1394c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *             boolean isCurrentlyActive) {
1395c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *         getDefaultUIUtil().onDraw(c, recyclerView,
1396c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *                 ((ItemTouchViewHolder) viewHolder).textView, dX, dY,
1397c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *                 actionState, isCurrentlyActive);
1398c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *         return true;
1399c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *     }
1400c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *     public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
1401c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *             RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
1402c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *             boolean isCurrentlyActive) {
1403c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *         getDefaultUIUtil().onDrawOver(c, recyclerView,
1404c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *                 ((ItemTouchViewHolder) viewHolder).textView, dX, dY,
1405c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *                 actionState, isCurrentlyActive);
1406c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *         return true;
1407c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *     }
1408c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * </pre>
1409c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         *
1410c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         * @return The {@link ItemTouchUIUtil} instance that is used by the {@link Callback}
1411c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar         */
1412c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar        public static ItemTouchUIUtil getDefaultUIUtil() {
1413c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar            return sUICallback;
1414c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar        }
1415c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar
1416c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar        /**
1417e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Replaces a movement direction with its relative version by taking layout direction into
1418e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * account.
1419e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1420e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param flags           The flag value that include any number of movement flags.
1421e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param layoutDirection The layout direction of the View. Can be obtained from
1422e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                        {@link ViewCompat#getLayoutDirection(android.view.View)}.
1423e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return Updated flags which uses relative flags ({@link #START}, {@link #END}) instead
1424e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * of {@link #LEFT}, {@link #RIGHT}.
1425e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @see #convertToAbsoluteDirection(int, int)
1426e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1427e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public static int convertToRelativeDirection(int flags, int layoutDirection) {
1428e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            int masked = flags & ABS_HORIZONTAL_DIR_FLAGS;
1429e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (masked == 0) {
1430e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return flags;// does not have any abs flags, good.
1431e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1432e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            flags &= ~masked; //remove left / right.
1433e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
1434e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // no change. just OR with 2 bits shifted mask and return
1435e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                flags |= masked << 2; // START is 2 bits after LEFT, END is 2 bits after RIGHT.
1436e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return flags;
1437e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else {
1438e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // add RIGHT flag as START
1439e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                flags |= ((masked << 1) & ~ABS_HORIZONTAL_DIR_FLAGS);
1440e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // first clean RIGHT bit then add LEFT flag as END
1441e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                flags |= ((masked << 1) & ABS_HORIZONTAL_DIR_FLAGS) << 2;
1442e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1443e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return flags;
1444e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1445e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1446e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1447e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Convenience method to create movement flags.
1448e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1449e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * For instance, if you want to let your items be drag & dropped vertically and swiped
1450e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * left to be dismissed, you can call this method with:
1451e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <code>makeMovementFlags(UP | DOWN, LEFT);</code>
1452e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1453e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param dragFlags  The directions in which the item can be dragged.
1454e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param swipeFlags The directions in which the item can be swiped.
1455e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return Returns an integer composed of the given drag and swipe flags.
1456e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1457e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public static int makeMovementFlags(int dragFlags, int swipeFlags) {
1458e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags) |
1459e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    makeFlag(ACTION_STATE_SWIPE, swipeFlags) | makeFlag(ACTION_STATE_DRAG,
1460e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    dragFlags);
1461e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1462e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1463e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1464e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Shifts the given direction flags to the offset of the given action state.
1465e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1466e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param actionState The action state you want to get flags in. Should be one of
1467e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    {@link #ACTION_STATE_IDLE}, {@link #ACTION_STATE_SWIPE} or
1468e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    {@link #ACTION_STATE_DRAG}.
1469e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param directions  The direction flags. Can be composed from {@link #UP}, {@link #DOWN},
1470e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    {@link #RIGHT}, {@link #LEFT} {@link #START} and {@link #END}.
1471e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return And integer that represents the given directions in the provided actionState.
1472e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1473e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public static int makeFlag(int actionState, int directions) {
1474e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return directions << (actionState * DIRECTION_FLAG_COUNT);
1475e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1476e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1477e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1478e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Should return a composite flag which defines the enabled move directions in each state
1479e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * (idle, swiping, dragging).
1480e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1481e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Instead of composing this flag manually, you can use {@link #makeMovementFlags(int,
1482e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * int)}
1483e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * or {@link #makeFlag(int, int)}.
1484e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1485e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * This flag is composed of 3 sets of 8 bits, where first 8 bits are for IDLE state, next
1486e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * 8 bits are for SWIPE state and third 8 bits are for DRAG state.
1487e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Each 8 bit sections can be constructed by simply OR'ing direction flags defined in
1488e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link ItemTouchHelper}.
1489e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1490e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * For example, if you want it to allow swiping LEFT and RIGHT but only allow starting to
1491e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * swipe by swiping RIGHT, you can return:
1492e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <pre>
1493e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *      makeFlag(ACTION_STATE_IDLE, RIGHT) | makeFlag(ACTION_STATE_SWIPE, LEFT | RIGHT);
1494e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * </pre>
1495e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * This means, allow right movement while IDLE and allow right and left movement while
1496e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * swiping.
1497e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1498e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView The RecyclerView to which ItemTouchHelper is attached.
1499e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder   The ViewHolder for which the movement information is necessary.
1500e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return flags specifying which movements are allowed on this ViewHolder.
1501e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @see #makeMovementFlags(int, int)
1502e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @see #makeFlag(int, int)
1503e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1504e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public abstract int getMovementFlags(RecyclerView recyclerView,
1505e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ViewHolder viewHolder);
1506e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1507e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1508e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Converts a given set of flags to absolution direction which means {@link #START} and
1509e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link #END} are replaced with {@link #LEFT} and {@link #RIGHT} depending on the layout
1510e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * direction.
1511e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1512e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param flags           The flag value that include any number of movement flags.
1513e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param layoutDirection The layout direction of the RecyclerView.
1514e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return Updated flags which includes only absolute direction values.
1515e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1516e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public int convertToAbsoluteDirection(int flags, int layoutDirection) {
1517e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            int masked = flags & RELATIVE_DIR_FLAGS;
1518e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (masked == 0) {
1519e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return flags;// does not have any relative flags, good.
1520e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1521e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            flags &= ~masked; //remove start / end
1522e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
1523e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // no change. just OR with 2 bits shifted mask and return
1524e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                flags |= masked >> 2; // START is 2 bits after LEFT, END is 2 bits after RIGHT.
1525e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return flags;
1526e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else {
1527e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // add START flag as RIGHT
1528e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                flags |= ((masked >> 1) & ~RELATIVE_DIR_FLAGS);
1529e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                // first clean start bit then add END flag as LEFT
1530e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                flags |= ((masked >> 1) & RELATIVE_DIR_FLAGS) >> 2;
1531e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1532e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return flags;
1533e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1534e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1535e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int getAbsoluteMovementFlags(RecyclerView recyclerView,
1536e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ViewHolder viewHolder) {
1537e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int flags = getMovementFlags(recyclerView, viewHolder);
1538e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return convertToAbsoluteDirection(flags, ViewCompat.getLayoutDirection(recyclerView));
1539e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1540e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1541e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private boolean hasDragFlag(RecyclerView recyclerView, ViewHolder viewHolder) {
1542e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int flags = getAbsoluteMovementFlags(recyclerView, viewHolder);
1543e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return (flags & ACTION_MODE_DRAG_MASK) != 0;
1544e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1545e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1546e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private boolean hasSwipeFlag(RecyclerView recyclerView,
1547e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ViewHolder viewHolder) {
1548e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int flags = getAbsoluteMovementFlags(recyclerView, viewHolder);
1549e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return (flags & ACTION_MODE_SWIPE_MASK) != 0;
1550e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1551e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1552e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1553e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Return true if the current ViewHolder can be dropped over the the target ViewHolder.
1554e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1555e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * This method is used when selecting drop target for the dragged View. After Views are
1556e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * eliminated either via bounds check or via this method, resulting set of views will be
1557e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * passed to {@link #chooseDropTarget(ViewHolder, java.util.List, int, int)}.
1558e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1559e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default implementation returns true.
1560e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1561e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView The RecyclerView to which ItemTouchHelper is attached to.
1562e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param current      The ViewHolder that user is dragging.
1563e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param target       The ViewHolder which is below the dragged ViewHolder.
1564e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return True if the dragged ViewHolder can be replaced with the target ViewHolder, false
1565e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * otherwise.
1566e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1567e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public boolean canDropOver(RecyclerView recyclerView, ViewHolder current,
1568e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ViewHolder target) {
1569e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return true;
1570e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1571e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1572e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1573e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called when ItemTouchHelper wants to move the dragged item from its old position to
1574e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * the new position.
1575e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1576e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * If this method returns true, ItemTouchHelper assumes {@code viewHolder} has been moved
1577e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * to the adapter position of {@code target} ViewHolder
1578e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * ({@link ViewHolder#getAdapterPosition()
1579e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * ViewHolder#getAdapterPosition()}).
1580e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1581e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * If you don't support drag & drop, this method will never be called.
1582e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1583e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView The RecyclerView to which ItemTouchHelper is attached to.
1584e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder   The ViewHolder which is being dragged by the user.
1585e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param target       The ViewHolder over which the currently active item is being
1586e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                     dragged.
1587e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return True if the {@code viewHolder} has been moved to the adapter position of
1588e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@code target}.
1589e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @see #onMoved(RecyclerView, ViewHolder, int, ViewHolder, int, int, int)
1590e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1591e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public abstract boolean onMove(RecyclerView recyclerView,
1592e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ViewHolder viewHolder, ViewHolder target);
1593e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1594e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1595e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Returns whether ItemTouchHelper should start a drag and drop operation if an item is
1596e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * long pressed.
1597e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1598e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default value returns true but you may want to disable this if you want to start
1599e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * dragging on a custom view touch using {@link #startDrag(ViewHolder)}.
1600e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1601e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return True if ItemTouchHelper should start dragging an item when it is long pressed,
1602e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * false otherwise. Default value is <code>true</code>.
1603e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @see #startDrag(ViewHolder)
1604e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1605e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public boolean isLongPressDragEnabled() {
1606e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return true;
1607e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1608e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1609e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1610e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Returns whether ItemTouchHelper should start a swipe operation if a pointer is swiped
1611e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * over the View.
1612e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1613e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default value returns true but you may want to disable this if you want to start
1614e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * swiping on a custom view touch using {@link #startSwipe(ViewHolder)}.
1615e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1616e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return True if ItemTouchHelper should start swiping an item when user swipes a pointer
1617e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * over the View, false otherwise. Default value is <code>true</code>.
1618e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @see #startSwipe(ViewHolder)
1619e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1620e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public boolean isItemViewSwipeEnabled() {
1621e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return true;
1622e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1623e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1624e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1625e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * When finding views under a dragged view, by default, ItemTouchHelper searches for views
1626e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * that overlap with the dragged View. By overriding this method, you can extend or shrink
1627e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * the search box.
1628e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1629e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return The extra margin to be added to the hit box of the dragged View.
1630e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1631e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public int getBoundingBoxMargin() {
1632e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return 0;
1633e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1634e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1635e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1636e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Returns the fraction that the user should move the View to be considered as swiped.
1637e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * The fraction is calculated with respect to RecyclerView's bounds.
1638e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1639e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default value is .5f, which means, to swipe a View, user must move the View at least
1640e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * half of RecyclerView's width or height, depending on the swipe direction.
1641e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1642e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder The ViewHolder that is being dragged.
1643e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return A float value that denotes the fraction of the View size. Default value
1644e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * is .5f .
1645e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1646e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public float getSwipeThreshold(ViewHolder viewHolder) {
1647e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return .5f;
1648e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1649e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1650e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1651e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Returns the fraction that the user should move the View to be considered as it is
1652e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * dragged. After a view is moved this amount, ItemTouchHelper starts checking for Views
1653e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * below it for a possible drop.
1654e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1655e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder The ViewHolder that is being dragged.
1656e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return A float value that denotes the fraction of the View size. Default value is
1657e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * .5f .
1658e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1659e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public float getMoveThreshold(ViewHolder viewHolder) {
1660e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return .5f;
1661e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1662e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1663e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1664e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called by ItemTouchHelper to select a drop target from the list of ViewHolders that
1665e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * are under the dragged View.
1666e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1667e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default implementation filters the View with which dragged item have changed position
1668e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * in the drag direction. For instance, if the view is dragged UP, it compares the
1669e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <code>view.getTop()</code> of the two views before and after drag started. If that value
1670e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * is different, the target view passes the filter.
1671e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1672e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Among these Views which pass the test, the one closest to the dragged view is chosen.
1673e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1674e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * This method is called on the main thread every time user moves the View. If you want to
1675e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * override it, make sure it does not do any expensive operations.
1676e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1677e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param selected    The ViewHolder being dragged by the user.
1678e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param dropTargets The list of ViewHolder that are under the dragged View and
1679e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    candidate as a drop.
1680e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param curX        The updated left value of the dragged View after drag translations
1681e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    are applied. This value does not include margins added by
1682e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    {@link RecyclerView.ItemDecoration}s.
1683e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param curY        The updated top value of the dragged View after drag translations
1684e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    are applied. This value does not include margins added by
1685e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    {@link RecyclerView.ItemDecoration}s.
1686e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return A ViewHolder to whose position the dragged ViewHolder should be
1687e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * moved to.
1688e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1689e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public ViewHolder chooseDropTarget(ViewHolder selected,
1690e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                List<ViewHolder> dropTargets, int curX, int curY) {
1691e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            int right = curX + selected.itemView.getWidth();
1692e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            int bottom = curY + selected.itemView.getHeight();
1693e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            ViewHolder winner = null;
1694e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            int winnerScore = -1;
1695e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int dx = curX - selected.itemView.getLeft();
1696e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int dy = curY - selected.itemView.getTop();
1697e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int targetsSize = dropTargets.size();
1698e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            for (int i = 0; i < targetsSize; i++) {
1699e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final ViewHolder target = dropTargets.get(i);
1700e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (dx > 0) {
1701e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    int diff = target.itemView.getRight() - right;
1702e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (diff < 0 && target.itemView.getRight() > selected.itemView.getRight()) {
1703e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        final int score = Math.abs(diff);
1704e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (score > winnerScore) {
1705e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            winnerScore = score;
1706e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            winner = target;
1707e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
1708e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
1709e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1710e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (dx < 0) {
1711e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    int diff = target.itemView.getLeft() - curX;
1712e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (diff > 0 && target.itemView.getLeft() < selected.itemView.getLeft()) {
1713e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        final int score = Math.abs(diff);
1714e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (score > winnerScore) {
1715e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            winnerScore = score;
1716e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            winner = target;
1717e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
1718e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
1719e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1720e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (dy < 0) {
1721e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    int diff = target.itemView.getTop() - curY;
1722e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (diff > 0 && target.itemView.getTop() < selected.itemView.getTop()) {
1723e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        final int score = Math.abs(diff);
1724e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (score > winnerScore) {
1725e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            winnerScore = score;
1726e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            winner = target;
1727e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
1728e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
1729e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1730e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1731e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (dy > 0) {
1732e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    int diff = target.itemView.getBottom() - bottom;
1733e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (diff < 0 && target.itemView.getBottom() > selected.itemView.getBottom()) {
1734e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        final int score = Math.abs(diff);
1735e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (score > winnerScore) {
1736e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            winnerScore = score;
1737e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            winner = target;
1738e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
1739e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
1740e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1741e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1742e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return winner;
1743e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1744e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1745e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1746e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called when a ViewHolder is swiped by the user.
1747e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1748e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * If you are returning relative directions ({@link #START} , {@link #END}) from the
1749e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link #getMovementFlags(RecyclerView, ViewHolder)} method, this method
1750e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * will also use relative directions. Otherwise, it will use absolute directions.
1751e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1752e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * If you don't support swiping, this method will never be called.
1753e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1754e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * ItemTouchHelper will keep a reference to the View until it is detached from
1755e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * RecyclerView.
1756e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * As soon as it is detached, ItemTouchHelper will call
1757e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link #clearView(RecyclerView, ViewHolder)}.
1758e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1759e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder The ViewHolder which has been swiped by the user.
1760e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param direction  The direction to which the ViewHolder is swiped. It is one of
1761e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                   {@link #UP}, {@link #DOWN},
1762e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                   {@link #LEFT} or {@link #RIGHT}. If your
1763e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                   {@link #getMovementFlags(RecyclerView, ViewHolder)}
1764e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                   method
1765e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                   returned relative flags instead of {@link #LEFT} / {@link #RIGHT};
1766e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                   `direction` will be relative as well. ({@link #START} or {@link
1767e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                   #END}).
1768e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1769e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public abstract void onSwiped(ViewHolder viewHolder, int direction);
1770e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1771e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1772e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called when the ViewHolder swiped or dragged by the ItemTouchHelper is changed.
1773e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p/>
1774e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * If you override this method, you should call super.
1775e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1776e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder  The new ViewHolder that is being swiped or dragged. Might be null if
1777e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    it is cleared.
1778e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param actionState One of {@link ItemTouchHelper#ACTION_STATE_IDLE},
1779e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    {@link ItemTouchHelper#ACTION_STATE_SWIPE} or
1780e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                    {@link ItemTouchHelper#ACTION_STATE_DRAG}.
1781e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1782e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @see #clearView(RecyclerView, RecyclerView.ViewHolder)
1783e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1784e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
1785e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (viewHolder != null) {
1786c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar                sUICallback.onSelected(viewHolder.itemView);
1787e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1788e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1789e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1790e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private int getMaxDragScroll(RecyclerView recyclerView) {
1791e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mCachedMaxScrollSpeed == -1) {
1792e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mCachedMaxScrollSpeed = recyclerView.getResources().getDimensionPixelSize(
1793e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        R.dimen.item_touch_helper_max_drag_scroll_per_frame);
1794e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1795e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return mCachedMaxScrollSpeed;
1796e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1797e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1798e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1799e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called when {@link #onMove(RecyclerView, ViewHolder, ViewHolder)} returns true.
1800e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1801e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * ItemTouchHelper does not create an extra Bitmap or View while dragging, instead, it
1802e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * modifies the existing View. Because of this reason, it is important that the View is
1803e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * still part of the layout after it is moved. This may not work as intended when swapped
1804e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Views are close to RecyclerView bounds or there are gaps between them (e.g. other Views
1805e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * which were not eligible for dropping over).
1806e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1807e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * This method is responsible to give necessary hint to the LayoutManager so that it will
1808e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * keep the View in visible area. For example, for LinearLayoutManager, this is as simple
1809e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * as calling {@link LinearLayoutManager#scrollToPositionWithOffset(int, int)}.
1810e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1811e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default implementation calls {@link RecyclerView#scrollToPosition(int)} if the View's
1812e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * new position is likely to be out of bounds.
1813e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1814e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * It is important to ensure the ViewHolder will stay visible as otherwise, it might be
1815e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * removed by the LayoutManager if the move causes the View to go out of bounds. In that
1816e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * case, drag will end prematurely.
1817e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1818e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView The RecyclerView controlled by the ItemTouchHelper.
1819e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder   The ViewHolder under user's control.
1820e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param fromPos      The previous adapter position of the dragged item (before it was
1821e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                     moved).
1822e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param target       The ViewHolder on which the currently active item has been dropped.
1823e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param toPos        The new adapter position of the dragged item.
1824e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param x            The updated left value of the dragged View after drag translations
1825e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                     are applied. This value does not include margins added by
1826e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                     {@link RecyclerView.ItemDecoration}s.
1827e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param y            The updated top value of the dragged View after drag translations
1828e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                     are applied. This value does not include margins added by
1829e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                     {@link RecyclerView.ItemDecoration}s.
1830e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1831e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onMoved(final RecyclerView recyclerView,
1832e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final ViewHolder viewHolder, int fromPos, final ViewHolder target, int toPos, int x,
1833e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                int y) {
1834e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
1835e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (layoutManager instanceof ViewDropHandler) {
1836e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ((ViewDropHandler) layoutManager).prepareForDrop(viewHolder.itemView,
1837e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        target.itemView, x, y);
1838e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return;
1839e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1840e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1841e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            // if layout manager cannot handle it, do some guesswork
1842e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (layoutManager.canScrollHorizontally()) {
1843e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int minLeft = layoutManager.getDecoratedLeft(target.itemView);
1844e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (minLeft <= recyclerView.getPaddingLeft()) {
1845e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    recyclerView.scrollToPosition(toPos);
1846e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1847e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int maxRight = layoutManager.getDecoratedRight(target.itemView);
1848e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (maxRight >= recyclerView.getWidth() - recyclerView.getPaddingRight()) {
1849e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    recyclerView.scrollToPosition(toPos);
1850e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1851e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1852e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1853e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (layoutManager.canScrollVertically()) {
1854e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int minTop = layoutManager.getDecoratedTop(target.itemView);
1855e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (minTop <= recyclerView.getPaddingTop()) {
1856e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    recyclerView.scrollToPosition(toPos);
1857e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1858e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int maxBottom = layoutManager.getDecoratedBottom(target.itemView);
1859e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (maxBottom >= recyclerView.getHeight() - recyclerView.getPaddingBottom()) {
1860e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    recyclerView.scrollToPosition(toPos);
1861e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1862e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1863e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1864e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1865e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private void onDraw(Canvas c, RecyclerView parent, ViewHolder selected,
1866e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                List<ItemTouchHelper.RecoverAnimation> recoverAnimationList,
1867e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                int actionState, float dX, float dY) {
1868e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int recoverAnimSize = recoverAnimationList.size();
1869e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            for (int i = 0; i < recoverAnimSize; i++) {
1870e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final ItemTouchHelper.RecoverAnimation anim = recoverAnimationList.get(i);
1871e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                anim.update();
1872e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int count = c.save();
1873e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                onChildDraw(c, parent, anim.mViewHolder, anim.mX, anim.mY, anim.mActionState,
1874e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        false);
1875e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                c.restoreToCount(count);
1876e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1877e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (selected != null) {
1878e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int count = c.save();
1879e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                onChildDraw(c, parent, selected, dX, dY, actionState, true);
1880e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                c.restoreToCount(count);
1881e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1882e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1883e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1884e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private void onDrawOver(Canvas c, RecyclerView parent, ViewHolder selected,
1885e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                List<ItemTouchHelper.RecoverAnimation> recoverAnimationList,
1886e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                int actionState, float dX, float dY) {
1887e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int recoverAnimSize = recoverAnimationList.size();
1888e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            for (int i = 0; i < recoverAnimSize; i++) {
1889e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final ItemTouchHelper.RecoverAnimation anim = recoverAnimationList.get(i);
1890e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int count = c.save();
1891e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                onChildDrawOver(c, parent, anim.mViewHolder, anim.mX, anim.mY, anim.mActionState,
1892e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        false);
1893e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                c.restoreToCount(count);
1894e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1895e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (selected != null) {
1896e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final int count = c.save();
1897e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                onChildDrawOver(c, parent, selected, dX, dY, actionState, true);
1898e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                c.restoreToCount(count);
1899e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1900e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            boolean hasRunningAnimation = false;
1901e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            for (int i = recoverAnimSize - 1; i >= 0; i--) {
1902e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                final RecoverAnimation anim = recoverAnimationList.get(i);
1903e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (anim.mEnded && !anim.mIsPendingCleanup) {
1904e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    recoverAnimationList.remove(i);
1905e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    anim.mViewHolder.setIsRecyclable(true);
1906e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                } else if (!anim.mEnded) {
1907e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    hasRunningAnimation = true;
1908e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
1909e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1910e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (hasRunningAnimation) {
1911e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                parent.invalidate();
1912e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
1913e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1914e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1915e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1916e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called by the ItemTouchHelper when the user interaction with an element is over and it
1917e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * also completed its animation.
1918e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1919e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * This is a good place to clear all changes on the View that was done in
1920e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link #onSelectedChanged(RecyclerView.ViewHolder, int)},
1921e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link #onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int,
1922e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * boolean)} or
1923e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, boolean)}.
1924e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1925e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView The RecyclerView which is controlled by the ItemTouchHelper.
1926e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder   The View that was interacted by the user.
1927e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1928e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {
1929c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar            sUICallback.clearView(viewHolder.itemView);
1930e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1931e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1932e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1933e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called by ItemTouchHelper on RecyclerView's onDraw callback.
1934e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1935e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * If you would like to customize how your View's respond to user interactions, this is
1936e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * a good place to override.
1937e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1938e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default implementation translates the child by the given <code>dX</code>,
1939e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <code>dY</code>.
1940e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * ItemTouchHelper also takes care of drawing the child after other children if it is being
1941e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * dragged. This is done using child re-ordering mechanism. On platforms prior to L, this
1942e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * is
1943e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * achieved via {@link android.view.ViewGroup#getChildDrawingOrder(int, int)} and on L
1944e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * and after, it changes View's elevation value to be greater than all other children.)
1945e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1946e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param c                 The canvas which RecyclerView is drawing its children
1947e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView      The RecyclerView to which ItemTouchHelper is attached to
1948e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder        The ViewHolder which is being interacted by the User or it was
1949e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                          interacted and simply animating to its original position
1950e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param dX                The amount of horizontal displacement caused by user's action
1951e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param dY                The amount of vertical displacement caused by user's action
1952e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param actionState       The type of interaction on the View. Is either {@link
1953e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                          #ACTION_STATE_DRAG} or {@link #ACTION_STATE_SWIPE}.
1954e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param isCurrentlyActive True if this view is currently being controlled by the user or
1955e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                          false it is simply animating back to its original state.
1956e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @see #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int,
1957e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * boolean)
1958e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1959e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onChildDraw(Canvas c, RecyclerView recyclerView,
1960e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ViewHolder viewHolder,
1961e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                float dX, float dY, int actionState, boolean isCurrentlyActive) {
1962c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar            sUICallback.onDraw(c, recyclerView, viewHolder.itemView, dX, dY, actionState,
1963c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar                    isCurrentlyActive);
1964e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1965e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1966e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
1967e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called by ItemTouchHelper on RecyclerView's onDraw callback.
1968e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1969e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * If you would like to customize how your View's respond to user interactions, this is
1970e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * a good place to override.
1971e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
1972e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default implementation translates the child by the given <code>dX</code>,
1973e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <code>dY</code>.
1974e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * ItemTouchHelper also takes care of drawing the child after other children if it is being
1975e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * dragged. This is done using child re-ordering mechanism. On platforms prior to L, this
1976e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * is
1977e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * achieved via {@link android.view.ViewGroup#getChildDrawingOrder(int, int)} and on L
1978e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * and after, it changes View's elevation value to be greater than all other children.)
1979e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
1980e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param c                 The canvas which RecyclerView is drawing its children
1981e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView      The RecyclerView to which ItemTouchHelper is attached to
1982e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder        The ViewHolder which is being interacted by the User or it was
1983e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                          interacted and simply animating to its original position
1984e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param dX                The amount of horizontal displacement caused by user's action
1985e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param dY                The amount of vertical displacement caused by user's action
1986e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param actionState       The type of interaction on the View. Is either {@link
1987e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                          #ACTION_STATE_DRAG} or {@link #ACTION_STATE_SWIPE}.
1988e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param isCurrentlyActive True if this view is currently being controlled by the user or
1989e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                          false it is simply animating back to its original state.
1990e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @see #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int,
1991e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * boolean)
1992e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
1993e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
1994e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ViewHolder viewHolder,
1995e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                float dX, float dY, int actionState, boolean isCurrentlyActive) {
1996c0459105252a3db52bc44ad62ecff4288860180dYigit Boyar            sUICallback.onDrawOver(c, recyclerView, viewHolder.itemView, dX, dY, actionState,
1997e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    isCurrentlyActive);
1998e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
1999e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2000e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
2001e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called by the ItemTouchHelper when user action finished on a ViewHolder and now the View
2002e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * will be animated to its final position.
2003e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
2004e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default implementation uses ItemAnimator's duration values. If
2005e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <code>animationType</code> is {@link #ANIMATION_TYPE_DRAG}, it returns
2006e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link RecyclerView.ItemAnimator#getMoveDuration()}, otherwise, it returns
2007e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link RecyclerView.ItemAnimator#getRemoveDuration()}. If RecyclerView does not have
2008e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * any {@link RecyclerView.ItemAnimator} attached, this method returns
2009e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@code DEFAULT_DRAG_ANIMATION_DURATION} or {@code DEFAULT_SWIPE_ANIMATION_DURATION}
2010e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * depending on the animation type.
2011e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
2012e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView  The RecyclerView to which the ItemTouchHelper is attached to.
2013e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param animationType The type of animation. Is one of {@link #ANIMATION_TYPE_DRAG},
2014e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                      {@link #ANIMATION_TYPE_SWIPE_CANCEL} or
2015e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                      {@link #ANIMATION_TYPE_SWIPE_SUCCESS}.
2016e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param animateDx     The horizontal distance that the animation will offset
2017e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param animateDy     The vertical distance that the animation will offset
2018e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return The duration for the animation
2019e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
2020e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public long getAnimationDuration(RecyclerView recyclerView, int animationType,
2021e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                float animateDx, float animateDy) {
2022e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final RecyclerView.ItemAnimator itemAnimator = recyclerView.getItemAnimator();
2023e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (itemAnimator == null) {
2024e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return animationType == ANIMATION_TYPE_DRAG ? DEFAULT_DRAG_ANIMATION_DURATION
2025e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        : DEFAULT_SWIPE_ANIMATION_DURATION;
2026e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else {
2027e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return animationType == ANIMATION_TYPE_DRAG ? itemAnimator.getMoveDuration()
2028e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        : itemAnimator.getRemoveDuration();
2029e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
2030e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2031e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2032e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
2033e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Called by the ItemTouchHelper when user is dragging a view out of bounds.
2034e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * <p>
2035e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * You can override this method to decide how much RecyclerView should scroll in response
2036e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * to this action. Default implementation calculates a value based on the amount of View
2037e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * out of bounds and the time it spent there. The longer user keeps the View out of bounds,
2038e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * the faster the list will scroll. Similarly, the larger portion of the View is out of
2039e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * bounds, the faster the RecyclerView will scroll.
2040e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
2041e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView        The RecyclerView instance to which ItemTouchHelper is attached
2042e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                            to.
2043e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewSize            The total size of the View in scroll direction, excluding
2044e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                            item decorations.
2045e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewSizeOutOfBounds The total size of the View that is out of bounds. This value
2046e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                            is negative if the View is dragged towards left or top edge.
2047e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param totalSize           The total size of RecyclerView in the scroll direction.
2048e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param msSinceStartScroll  The time passed since View is kept out of bounds.
2049e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
2050e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return The amount that RecyclerView should scroll. Keep in mind that this value will
2051e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * be passed to {@link RecyclerView#scrollBy(int, int)} method.
2052e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
2053e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public int interpolateOutOfBoundsScroll(RecyclerView recyclerView,
2054e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                int viewSize, int viewSizeOutOfBounds,
2055e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                int totalSize, long msSinceStartScroll) {
2056e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int maxScroll = getMaxDragScroll(recyclerView);
2057e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int absOutOfBounds = Math.abs(viewSizeOutOfBounds);
2058e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int direction = (int) Math.signum(viewSizeOutOfBounds);
2059e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            // might be negative if other direction
2060e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            float outOfBoundsRatio = Math.min(1f, 1f * absOutOfBounds / viewSize);
2061e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int cappedScroll = (int) (direction * maxScroll *
2062e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    sDragViewScrollCapInterpolator.getInterpolation(outOfBoundsRatio));
2063e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final float timeRatio;
2064e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (msSinceStartScroll > DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS) {
2065e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                timeRatio = 1f;
2066e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else {
2067e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                timeRatio = (float) msSinceStartScroll / DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS;
2068e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
2069e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final int value = (int) (cappedScroll * sDragScrollInterpolator
2070e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    .getInterpolation(timeRatio));
2071e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (value == 0) {
2072e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return viewSizeOutOfBounds > 0 ? 1 : -1;
2073e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
2074e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return value;
2075e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2076e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
2077e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2078e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
2079e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * A simple wrapper to the default Callback which you can construct with drag and swipe
2080e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * directions and this class will handle the flag callbacks. You should still override onMove
2081e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * or
2082e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * onSwiped depending on your use case.
2083e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *
2084e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * <pre>
2085e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * ItemTouchHelper mIth = new ItemTouchHelper(
2086e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *     new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
2087e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *         ItemTouchHelper.LEFT) {
2088e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *         public abstract boolean onMove(RecyclerView recyclerView,
2089e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             ViewHolder viewHolder, ViewHolder target) {
2090e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             final int fromPos = viewHolder.getAdapterPosition();
2091e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             final int toPos = viewHolder.getAdapterPosition();
2092e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             // move item in `fromPos` to `toPos` in adapter.
2093e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             return true;// true if moved, false otherwise
2094e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *         }
2095e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *         public void onSwiped(ViewHolder viewHolder, int direction) {
2096e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *             // remove from adapter
2097e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     *         }
2098e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * });
2099e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * </pre>
2100e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
2101e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public abstract static class SimpleCallback extends Callback {
2102e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2103e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private int mDefaultSwipeDirs;
2104e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2105e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private int mDefaultDragDirs;
2106e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2107e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
2108e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Creates a Callback for the given drag and swipe allowance. These values serve as
2109e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * defaults
2110e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * and if you want to customize behavior per ViewHolder, you can override
2111e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link #getSwipeDirs(RecyclerView, ViewHolder)}
2112e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * and / or {@link #getDragDirs(RecyclerView, ViewHolder)}.
2113e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
2114e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param dragDirs  Binary OR of direction flags in which the Views can be dragged. Must be
2115e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                  composed of {@link #LEFT}, {@link #RIGHT}, {@link #START}, {@link
2116e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                  #END},
2117e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                  {@link #UP} and {@link #DOWN}.
2118e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param swipeDirs Binary OR of direction flags in which the Views can be swiped. Must be
2119e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                  composed of {@link #LEFT}, {@link #RIGHT}, {@link #START}, {@link
2120e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                  #END},
2121e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *                  {@link #UP} and {@link #DOWN}.
2122e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
2123e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public SimpleCallback(int dragDirs, int swipeDirs) {
2124e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDefaultSwipeDirs = swipeDirs;
2125e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDefaultDragDirs = dragDirs;
2126e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2127e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2128e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
2129e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Updates the default swipe directions. For example, you can use this method to toggle
2130e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * certain directions depending on your use case.
2131e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
2132e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param defaultSwipeDirs Binary OR of directions in which the ViewHolders can be swiped.
2133e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
2134e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void setDefaultSwipeDirs(int defaultSwipeDirs) {
2135e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDefaultSwipeDirs = defaultSwipeDirs;
2136e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2137e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2138e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
2139e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Updates the default drag directions. For example, you can use this method to toggle
2140e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * certain directions depending on your use case.
2141e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
2142e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param defaultDragDirs Binary OR of directions in which the ViewHolders can be dragged.
2143e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
2144e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void setDefaultDragDirs(int defaultDragDirs) {
2145e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mDefaultDragDirs = defaultDragDirs;
2146e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2147e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2148e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
2149e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Returns the swipe directions for the provided ViewHolder.
2150e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default implementation returns the swipe directions that was set via constructor or
2151e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link #setDefaultSwipeDirs(int)}.
2152e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
2153e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView The RecyclerView to which the ItemTouchHelper is attached to.
2154e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder   The RecyclerView for which the swipe drection is queried.
2155e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return A binary OR of direction flags.
2156e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
2157e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public int getSwipeDirs(RecyclerView recyclerView, ViewHolder viewHolder) {
2158e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return mDefaultSwipeDirs;
2159e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2160e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2161e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
2162e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Returns the drag directions for the provided ViewHolder.
2163e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * Default implementation returns the drag directions that was set via constructor or
2164e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * {@link #setDefaultDragDirs(int)}.
2165e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         *
2166e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param recyclerView The RecyclerView to which the ItemTouchHelper is attached to.
2167e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @param viewHolder   The RecyclerView for which the swipe drection is queried.
2168e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * @return A binary OR of direction flags.
2169e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
2170e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public int getDragDirs(RecyclerView recyclerView, ViewHolder viewHolder) {
2171e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return mDefaultDragDirs;
2172e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2173e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2174e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
2175e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
2176e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return makeMovementFlags(getDragDirs(recyclerView, viewHolder),
2177e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    getSwipeDirs(recyclerView, viewHolder));
2178e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2179e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
2180e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2181e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener {
2182e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2183e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
2184e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public boolean onDown(MotionEvent e) {
2185e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return true;
2186e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2187e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2188e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
2189e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onLongPress(MotionEvent e) {
2190e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            View child = findChildView(e);
2191e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (child != null) {
2192e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                ViewHolder vh = mRecyclerView.getChildViewHolder(child);
2193e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (vh != null) {
2194e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (!mCallback.hasDragFlag(mRecyclerView, vh)) {
2195e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        return;
2196e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
2197e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    int pointerId = MotionEventCompat.getPointerId(e, 0);
2198e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    // Long press is deferred.
2199e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    // Check w/ active pointer id to avoid selecting after motion
2200e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    // event is canceled.
2201e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    if (pointerId == mActivePointerId) {
2202e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        final int index = MotionEventCompat
2203e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                                .findPointerIndex(e, mActivePointerId);
2204e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        final float x = MotionEventCompat.getX(e, index);
2205e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        final float y = MotionEventCompat.getY(e, index);
2206e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mInitialTouchX = x;
2207e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mInitialTouchY = y;
2208e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        mDx = mDy = 0f;
2209e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (DEBUG) {
2210e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            Log.d(TAG,
2211e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                                    "onlong press: x:" + mInitialTouchX + ",y:" + mInitialTouchY);
2212e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
2213e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        if (mCallback.isLongPressDragEnabled()) {
2214e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            select(vh, ACTION_STATE_DRAG);
2215e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
2216e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    }
2217e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
2218e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
2219e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2220e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
2221e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2222e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private class RecoverAnimation implements AnimatorListenerCompat {
2223e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2224e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float mStartDx;
2225e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2226e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float mStartDy;
2227e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2228e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float mTargetX;
2229e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2230e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final float mTargetY;
2231e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2232e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final ViewHolder mViewHolder;
2233e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2234e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int mActionState;
2235e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2236e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private final ValueAnimatorCompat mValueAnimator;
2237e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2238e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private final int mAnimationType;
2239e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2240e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public boolean mIsPendingCleanup;
2241e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2242e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        float mX;
2243e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2244e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        float mY;
2245e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2246e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // if user starts touching a recovering view, we put it into interaction mode again,
2247e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // instantly.
2248e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        boolean mOverridden = false;
2249e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2250e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private boolean mEnded = false;
2251e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2252e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private float mFraction;
2253e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2254e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public RecoverAnimation(ViewHolder viewHolder, int animationType,
2255e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                int actionState, float startDx, float startDy, float targetX, float targetY) {
2256e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mActionState = actionState;
2257e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mAnimationType = animationType;
2258e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mViewHolder = viewHolder;
2259e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mStartDx = startDx;
2260e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mStartDy = startDy;
2261e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mTargetX = targetX;
2262e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mTargetY = targetY;
2263e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mValueAnimator = AnimatorCompatHelper.emptyValueAnimator();
2264e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mValueAnimator.addUpdateListener(
2265e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    new AnimatorUpdateListenerCompat() {
2266e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        @Override
2267e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        public void onAnimationUpdate(ValueAnimatorCompat animation) {
2268e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                            setFraction(animation.getAnimatedFraction());
2269e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                        }
2270e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    });
2271e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mValueAnimator.setTarget(viewHolder.itemView);
2272e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mValueAnimator.addListener(this);
2273e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            setFraction(0f);
2274e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2275e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2276e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void setDuration(long duration) {
2277e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mValueAnimator.setDuration(duration);
2278e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2279e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2280e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void start() {
2281e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mViewHolder.setIsRecyclable(false);
2282e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mValueAnimator.start();
2283e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2284e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2285e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void cancel() {
2286e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mValueAnimator.cancel();
2287e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2288e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2289e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void setFraction(float fraction) {
2290e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mFraction = fraction;
2291e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2292e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2293e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        /**
2294e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * We run updates on onDraw method but use the fraction from animator callback.
2295e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         * This way, we can sync translate x/y values w/ the animators to avoid one-off frames.
2296e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar         */
2297e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void update() {
2298e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mStartDx == mTargetX) {
2299e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mX = ViewCompat.getTranslationX(mViewHolder.itemView);
2300e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else {
2301e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mX = mStartDx + mFraction * (mTargetX - mStartDx);
2302e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
2303e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (mStartDy == mTargetY) {
2304e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mY = ViewCompat.getTranslationY(mViewHolder.itemView);
2305e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else {
2306e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                mY = mStartDy + mFraction * (mTargetY - mStartDy);
2307e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
2308e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2309e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2310e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
2311e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onAnimationStart(ValueAnimatorCompat animation) {
2312e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2313e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2314e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2315e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
2316e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onAnimationEnd(ValueAnimatorCompat animation) {
2317e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mEnded = true;
2318e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2319e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2320e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
2321e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onAnimationCancel(ValueAnimatorCompat animation) {
2322e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            setFraction(1f); //make sure we recover the view's state.
2323e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2324e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2325e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
2326e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public void onAnimationRepeat(ValueAnimatorCompat animation) {
2327e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2328e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2329e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
2330e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar}