1d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase/*
2d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Copyright (C) 2014 The Android Open Source Project
3d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
4d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Licensed under the Apache License, Version 2.0 (the "License");
5d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * you may not use this file except in compliance with the License.
6d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * You may obtain a copy of the License at
7d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
8d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *      http://www.apache.org/licenses/LICENSE-2.0
9d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
10d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Unless required by applicable law or agreed to in writing, software
11d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * distributed under the License is distributed on an "AS IS" BASIS,
12d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * See the License for the specific language governing permissions and
14d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * limitations under the License.
15d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase */
16d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepackage android.support.v7.widget;
17d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
18ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikasimport android.animation.Animator;
19ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikasimport android.animation.AnimatorListenerAdapter;
20ae7189188acb2bc972b08d9fbd59939f341c7829Aurimas Liutikasimport android.animation.TimeInterpolator;
21ae7189188acb2bc972b08d9fbd59939f341c7829Aurimas Liutikasimport android.animation.ValueAnimator;
22abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyarimport android.support.annotation.NonNull;
23d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport android.support.v4.view.ViewCompat;
24d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport android.support.v7.widget.RecyclerView.ViewHolder;
25d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport android.view.View;
26ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikasimport android.view.ViewPropertyAnimator;
27d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
28d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.ArrayList;
29a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyarimport java.util.List;
30d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
31d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase/**
32d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * This implementation of {@link RecyclerView.ItemAnimator} provides basic
33d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * animations on remove, add, and move events that happen to the items in
34d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * a RecyclerView. RecyclerView uses a DefaultItemAnimator by default.
35d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
36d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
37d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase */
38121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarpublic class DefaultItemAnimator extends SimpleItemAnimator {
39a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    private static final boolean DEBUG = false;
40d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
41ae7189188acb2bc972b08d9fbd59939f341c7829Aurimas Liutikas    private static TimeInterpolator sDefaultInterpolator;
42ae7189188acb2bc972b08d9fbd59939f341c7829Aurimas Liutikas
43e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
44e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>();
45e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
46e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
47d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
483a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList<>();
493a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
503a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
51d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
523a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    ArrayList<ViewHolder> mAddAnimations = new ArrayList<>();
533a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>();
543a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>();
553a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>();
56d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
57d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private static class MoveInfo {
58d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public ViewHolder holder;
59d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public int fromX, fromY, toX, toY;
60d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
613a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas        MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
62d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.holder = holder;
63d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.fromX = fromX;
64d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.fromY = fromY;
65d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.toX = toX;
66d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.toY = toY;
67d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
68d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
69d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
70235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    private static class ChangeInfo {
71235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        public ViewHolder oldHolder, newHolder;
72a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        public int fromX, fromY, toX, toY;
73235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) {
74235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            this.oldHolder = oldHolder;
75235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            this.newHolder = newHolder;
76235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
77a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
783a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas        ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder,
79a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                int fromX, int fromY, int toX, int toY) {
80a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            this(oldHolder, newHolder);
81a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            this.fromX = fromX;
82a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            this.fromY = fromY;
83a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            this.toX = toX;
84a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            this.toY = toY;
85a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
86a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
87a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        @Override
88a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        public String toString() {
891e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            return "ChangeInfo{"
901e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + "oldHolder=" + oldHolder
911e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + ", newHolder=" + newHolder
921e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + ", fromX=" + fromX
931e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + ", fromY=" + fromY
941e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + ", toX=" + toX
951e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + ", toY=" + toY
961e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + '}';
97a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
98235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    }
99235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase
100d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
101d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void runPendingAnimations() {
102d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        boolean removalsPending = !mPendingRemovals.isEmpty();
103d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        boolean movesPending = !mPendingMoves.isEmpty();
104235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        boolean changesPending = !mPendingChanges.isEmpty();
105d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        boolean additionsPending = !mPendingAdditions.isEmpty();
106a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
107d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            // nothing to animate
108d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            return;
109d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
110d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // First, remove stuff
111d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        for (ViewHolder holder : mPendingRemovals) {
112d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            animateRemoveImpl(holder);
113d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
114d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingRemovals.clear();
115d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // Next, move stuff
116d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (movesPending) {
117e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            final ArrayList<MoveInfo> moves = new ArrayList<>();
1180e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            moves.addAll(mPendingMoves);
1190e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            mMovesList.add(moves);
120d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mPendingMoves.clear();
121d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            Runnable mover = new Runnable() {
122d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                @Override
123d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                public void run() {
1240e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    for (MoveInfo moveInfo : moves) {
125d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
126d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                                moveInfo.toX, moveInfo.toY);
127d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
1280e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    moves.clear();
1290e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mMovesList.remove(moves);
130d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
131d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            };
132d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            if (removalsPending) {
1330e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                View view = moves.get(0).holder.itemView;
134d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration());
135d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            } else {
136d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                mover.run();
137d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
138d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
139235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        // Next, change stuff, to run in parallel with move animations
140235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        if (changesPending) {
141e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            final ArrayList<ChangeInfo> changes = new ArrayList<>();
1420e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            changes.addAll(mPendingChanges);
1430e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            mChangesList.add(changes);
144235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            mPendingChanges.clear();
145235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            Runnable changer = new Runnable() {
146235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                @Override
147235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                public void run() {
1480e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    for (ChangeInfo change : changes) {
149235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                        animateChangeImpl(change);
150235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                    }
1510e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    changes.clear();
1520e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mChangesList.remove(changes);
153235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                }
154235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            };
155235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            if (removalsPending) {
1560e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                ViewHolder holder = changes.get(0).oldHolder;
157235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration());
158235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            } else {
159235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                changer.run();
160235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            }
161235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
162d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // Next, add stuff
163d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (additionsPending) {
164e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            final ArrayList<ViewHolder> additions = new ArrayList<>();
1650e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            additions.addAll(mPendingAdditions);
1660e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            mAdditionsList.add(additions);
167d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mPendingAdditions.clear();
168d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            Runnable adder = new Runnable() {
169dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas                @Override
170d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                public void run() {
1710e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    for (ViewHolder holder : additions) {
172d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        animateAddImpl(holder);
173d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
1740e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    additions.clear();
1750e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mAdditionsList.remove(additions);
176d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
177d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            };
178549bbdfca3cffe64fd3ef69723a54037df326689Chet Haase            if (removalsPending || movesPending || changesPending) {
179235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                long removeDuration = removalsPending ? getRemoveDuration() : 0;
180235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                long moveDuration = movesPending ? getMoveDuration() : 0;
181235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                long changeDuration = changesPending ? getChangeDuration() : 0;
182235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
1830e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                View view = additions.get(0).itemView;
184235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
185d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            } else {
186d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                adder.run();
187d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
188d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
189d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
190d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
191d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
192d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean animateRemove(final ViewHolder holder) {
193d03a495b04ee74c1cb493cee0d5998b895b1c79bVladislav Kaznacheev        resetAnimation(holder);
194d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingRemovals.add(holder);
195d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return true;
196d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
197d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
198d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private void animateRemoveImpl(final ViewHolder holder) {
199d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
200ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        final ViewPropertyAnimator animation = view.animate();
2014d21e073e1aa2eb08777c288d08a92c419faa1e9Yigit Boyar        mRemoveAnimations.add(holder);
202ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        animation.setDuration(getRemoveDuration()).alpha(0).setListener(
203ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                new AnimatorListenerAdapter() {
204ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    @Override
205ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    public void onAnimationStart(Animator animator) {
206ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        dispatchRemoveStarting(holder);
207ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    }
2084d21e073e1aa2eb08777c288d08a92c419faa1e9Yigit Boyar
209ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    @Override
210ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    public void onAnimationEnd(Animator animator) {
211ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        animation.setListener(null);
212ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        view.setAlpha(1);
213ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        dispatchRemoveFinished(holder);
214ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        mRemoveAnimations.remove(holder);
215ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        dispatchFinishedWhenDone();
216ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    }
217ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                }).start();
218d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
219d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
220d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
221d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean animateAdd(final ViewHolder holder) {
222d03a495b04ee74c1cb493cee0d5998b895b1c79bVladislav Kaznacheev        resetAnimation(holder);
223ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        holder.itemView.setAlpha(0);
224d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingAdditions.add(holder);
225d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return true;
226d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
227d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
2283a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    void animateAddImpl(final ViewHolder holder) {
229d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
230ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        final ViewPropertyAnimator animation = view.animate();
2314d21e073e1aa2eb08777c288d08a92c419faa1e9Yigit Boyar        mAddAnimations.add(holder);
232ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        animation.alpha(1).setDuration(getAddDuration())
233ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                .setListener(new AnimatorListenerAdapter() {
234d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    @Override
235ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    public void onAnimationStart(Animator animator) {
236e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                        dispatchAddStarting(holder);
237e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                    }
238ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas
239e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                    @Override
240ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    public void onAnimationCancel(Animator animator) {
241ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        view.setAlpha(1);
242d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
243c35968d173f900d8024bdf38174e2225c9a7f311Chet Haase
244d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    @Override
245ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    public void onAnimationEnd(Animator animator) {
24607715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu                        animation.setListener(null);
247d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        dispatchAddFinished(holder);
248d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        mAddAnimations.remove(holder);
249d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        dispatchFinishedWhenDone();
250d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
251d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }).start();
252d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
253d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
254d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
255d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean animateMove(final ViewHolder holder, int fromX, int fromY,
256d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            int toX, int toY) {
257d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
2586bebe14261b8f3f17ef5059f00d077c7b81561ccAurimas Liutikas        fromX += (int) holder.itemView.getTranslationX();
2596bebe14261b8f3f17ef5059f00d077c7b81561ccAurimas Liutikas        fromY += (int) holder.itemView.getTranslationY();
260d03a495b04ee74c1cb493cee0d5998b895b1c79bVladislav Kaznacheev        resetAnimation(holder);
261d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        int deltaX = toX - fromX;
262d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        int deltaY = toY - fromY;
263d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaX == 0 && deltaY == 0) {
264d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchMoveFinished(holder);
265d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            return false;
266d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
267d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaX != 0) {
268ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            view.setTranslationX(-deltaX);
269d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
270d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaY != 0) {
271ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            view.setTranslationY(-deltaY);
272d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
273d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
274d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return true;
275d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
276d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
2773a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) {
278d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
279d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final int deltaX = toX - fromX;
280d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final int deltaY = toY - fromY;
281d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaX != 0) {
282ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            view.animate().translationX(0);
283d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
284d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaY != 0) {
285ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            view.animate().translationY(0);
286d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
287d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // TODO: make EndActions end listeners instead, since end actions aren't called when
288d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // vpas are canceled (and can't end them. why?)
289d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // need listener functionality in VPACompat for this. Ick.
290ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        final ViewPropertyAnimator animation = view.animate();
2914d21e073e1aa2eb08777c288d08a92c419faa1e9Yigit Boyar        mMoveAnimations.add(holder);
292ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        animation.setDuration(getMoveDuration()).setListener(new AnimatorListenerAdapter() {
293d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
294ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            public void onAnimationStart(Animator animator) {
295e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                dispatchMoveStarting(holder);
296e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            }
297ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas
298e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            @Override
299ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            public void onAnimationCancel(Animator animator) {
300d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                if (deltaX != 0) {
301ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    view.setTranslationX(0);
302d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
303d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                if (deltaY != 0) {
304ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    view.setTranslationY(0);
305d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
306d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
307ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas
308d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
309ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            public void onAnimationEnd(Animator animator) {
31007715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu                animation.setListener(null);
311d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                dispatchMoveFinished(holder);
312d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                mMoveAnimations.remove(holder);
313d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                dispatchFinishedWhenDone();
314d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
315d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }).start();
316d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
317d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
318d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
319a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
320a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            int fromX, int fromY, int toX, int toY) {
321121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        if (oldHolder == newHolder) {
322121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            // Don't know how to run change animations when the same view holder is re-used.
323121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            // run a move animation to handle position changes.
324121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return animateMove(oldHolder, fromX, fromY, toX, toY);
325121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
326ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        final float prevTranslationX = oldHolder.itemView.getTranslationX();
327ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        final float prevTranslationY = oldHolder.itemView.getTranslationY();
328ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        final float prevAlpha = oldHolder.itemView.getAlpha();
329d03a495b04ee74c1cb493cee0d5998b895b1c79bVladislav Kaznacheev        resetAnimation(oldHolder);
330a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        int deltaX = (int) (toX - fromX - prevTranslationX);
331a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        int deltaY = (int) (toY - fromY - prevTranslationY);
332a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        // recover prev translation state after ending animation
333ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        oldHolder.itemView.setTranslationX(prevTranslationX);
334ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        oldHolder.itemView.setTranslationY(prevTranslationY);
335ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        oldHolder.itemView.setAlpha(prevAlpha);
336e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        if (newHolder != null) {
337a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            // carry over translation values
338d03a495b04ee74c1cb493cee0d5998b895b1c79bVladislav Kaznacheev            resetAnimation(newHolder);
339ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            newHolder.itemView.setTranslationX(-deltaX);
340ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            newHolder.itemView.setTranslationY(-deltaY);
341ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            newHolder.itemView.setAlpha(0);
342235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
343a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
344235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        return true;
345235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    }
346235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase
3473a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    void animateChangeImpl(final ChangeInfo changeInfo) {
348235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        final ViewHolder holder = changeInfo.oldHolder;
34990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        final View view = holder == null ? null : holder.itemView;
350235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        final ViewHolder newHolder = changeInfo.newHolder;
351235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        final View newView = newHolder != null ? newHolder.itemView : null;
35290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        if (view != null) {
353ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            final ViewPropertyAnimator oldViewAnim = view.animate().setDuration(
35490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    getChangeDuration());
3554d21e073e1aa2eb08777c288d08a92c419faa1e9Yigit Boyar            mChangeAnimations.add(changeInfo.oldHolder);
35690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);
35790ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);
358ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            oldViewAnim.alpha(0).setListener(new AnimatorListenerAdapter() {
35990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                @Override
360ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                public void onAnimationStart(Animator animator) {
36190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    dispatchChangeStarting(changeInfo.oldHolder, true);
36290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                }
363a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
36490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                @Override
365ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                public void onAnimationEnd(Animator animator) {
36690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    oldViewAnim.setListener(null);
367ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    view.setAlpha(1);
368ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    view.setTranslationX(0);
369ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    view.setTranslationY(0);
37090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    dispatchChangeFinished(changeInfo.oldHolder, true);
37190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    mChangeAnimations.remove(changeInfo.oldHolder);
37290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    dispatchFinishedWhenDone();
37390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                }
37490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            }).start();
37590ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        }
376235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        if (newView != null) {
377f18d9dcf92e0103b163491b1fcf242e18ec1e59eAurimas Liutikas            final ViewPropertyAnimator newViewAnimation = newView.animate();
3784d21e073e1aa2eb08777c288d08a92c419faa1e9Yigit Boyar            mChangeAnimations.add(changeInfo.newHolder);
3791e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration())
3801e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    .alpha(1).setListener(new AnimatorListenerAdapter() {
381ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        @Override
382ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        public void onAnimationStart(Animator animator) {
383ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                            dispatchChangeStarting(changeInfo.newHolder, false);
384ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        }
385ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        @Override
386ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        public void onAnimationEnd(Animator animator) {
387ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                            newViewAnimation.setListener(null);
388ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                            newView.setAlpha(1);
389ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                            newView.setTranslationX(0);
390ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                            newView.setTranslationY(0);
391ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                            dispatchChangeFinished(changeInfo.newHolder, false);
392ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                            mChangeAnimations.remove(changeInfo.newHolder);
393ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                            dispatchFinishedWhenDone();
394ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                        }
395ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    }).start();
396235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
397a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    }
398a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
399a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    private void endChangeAnimation(List<ChangeInfo> infoList, ViewHolder item) {
400a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        for (int i = infoList.size() - 1; i >= 0; i--) {
401a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            ChangeInfo changeInfo = infoList.get(i);
402a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            if (endChangeAnimationIfNecessary(changeInfo, item)) {
403a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
404a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    infoList.remove(changeInfo);
405a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                }
406a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            }
407a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
408a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    }
409a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
410a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) {
411a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (changeInfo.oldHolder != null) {
412a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder);
413a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
414a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (changeInfo.newHolder != null) {
415a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder);
416a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
417a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    }
418a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) {
419e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase        boolean oldItem = false;
420a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (changeInfo.newHolder == item) {
421a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            changeInfo.newHolder = null;
422a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        } else if (changeInfo.oldHolder == item) {
423a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            changeInfo.oldHolder = null;
424e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            oldItem = true;
425a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        } else {
426a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            return false;
427a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
428ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        item.itemView.setAlpha(1);
429ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        item.itemView.setTranslationX(0);
430ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        item.itemView.setTranslationY(0);
431e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase        dispatchChangeFinished(item, oldItem);
432a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        return true;
433235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    }
434235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase
435235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    @Override
436d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void endAnimation(ViewHolder item) {
437d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = item.itemView;
438a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        // this will trigger end callback which should set properties to their target values.
439ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas        view.animate().cancel();
440a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        // TODO if some other animations are chained to end, how do we cancel them as well?
441235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
442235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            MoveInfo moveInfo = mPendingMoves.get(i);
443235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            if (moveInfo.holder == item) {
444ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                view.setTranslationY(0);
445ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                view.setTranslationX(0);
446235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                dispatchMoveFinished(item);
4479457c0c167cca5aafe971fb2eb75f4a43c07ec05Yigit Boyar                mPendingMoves.remove(i);
448235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            }
44993b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        }
450a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        endChangeAnimation(mPendingChanges, item);
451a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mPendingRemovals.remove(item)) {
452ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            view.setAlpha(1);
45393b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            dispatchRemoveFinished(item);
45493b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        }
455a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mPendingAdditions.remove(item)) {
456ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            view.setAlpha(1);
45793b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            dispatchAddFinished(item);
458235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
459a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
4600e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = mChangesList.size() - 1; i >= 0; i--) {
4610e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<ChangeInfo> changes = mChangesList.get(i);
4620e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            endChangeAnimation(changes, item);
4630e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            if (changes.isEmpty()) {
4649457c0c167cca5aafe971fb2eb75f4a43c07ec05Yigit Boyar                mChangesList.remove(i);
465ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu            }
466ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu        }
4670e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = mMovesList.size() - 1; i >= 0; i--) {
4680e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<MoveInfo> moves = mMovesList.get(i);
4690e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            for (int j = moves.size() - 1; j >= 0; j--) {
4700e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                MoveInfo moveInfo = moves.get(j);
4710e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                if (moveInfo.holder == item) {
472ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    view.setTranslationY(0);
473ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                    view.setTranslationX(0);
4740e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    dispatchMoveFinished(item);
4750e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    moves.remove(j);
4760e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    if (moves.isEmpty()) {
4779457c0c167cca5aafe971fb2eb75f4a43c07ec05Yigit Boyar                        mMovesList.remove(i);
4780e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    }
4790e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    break;
4800e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                }
4810e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            }
4820e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        }
4830e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
4840e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<ViewHolder> additions = mAdditionsList.get(i);
4850e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            if (additions.remove(item)) {
486ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                view.setAlpha(1);
4870e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                dispatchAddFinished(item);
4880e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                if (additions.isEmpty()) {
4899457c0c167cca5aafe971fb2eb75f4a43c07ec05Yigit Boyar                    mAdditionsList.remove(i);
4900e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                }
4910e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            }
492ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu        }
493a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
494a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        // animations should be ended by the cancel above.
495e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        //noinspection PointlessBooleanExpression,ConstantConditions
496a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mRemoveAnimations.remove(item) && DEBUG) {
497a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            throw new IllegalStateException("after animation is cancelled, item should not be in "
498a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    + "mRemoveAnimations list");
499d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
500a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
501e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        //noinspection PointlessBooleanExpression,ConstantConditions
502a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mAddAnimations.remove(item) && DEBUG) {
503a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            throw new IllegalStateException("after animation is cancelled, item should not be in "
504a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    + "mAddAnimations list");
505d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
506a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
507e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        //noinspection PointlessBooleanExpression,ConstantConditions
508a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mChangeAnimations.remove(item) && DEBUG) {
509a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            throw new IllegalStateException("after animation is cancelled, item should not be in "
510a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    + "mChangeAnimations list");
511a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
512a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
513e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        //noinspection PointlessBooleanExpression,ConstantConditions
514a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mMoveAnimations.remove(item) && DEBUG) {
515a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            throw new IllegalStateException("after animation is cancelled, item should not be in "
516a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    + "mMoveAnimations list");
517235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
518d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        dispatchFinishedWhenDone();
519d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
520d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
521d03a495b04ee74c1cb493cee0d5998b895b1c79bVladislav Kaznacheev    private void resetAnimation(ViewHolder holder) {
522ae7189188acb2bc972b08d9fbd59939f341c7829Aurimas Liutikas        if (sDefaultInterpolator == null) {
523ae7189188acb2bc972b08d9fbd59939f341c7829Aurimas Liutikas            sDefaultInterpolator = new ValueAnimator().getInterpolator();
524ae7189188acb2bc972b08d9fbd59939f341c7829Aurimas Liutikas        }
525ae7189188acb2bc972b08d9fbd59939f341c7829Aurimas Liutikas        holder.itemView.animate().setInterpolator(sDefaultInterpolator);
526d03a495b04ee74c1cb493cee0d5998b895b1c79bVladislav Kaznacheev        endAnimation(holder);
527d03a495b04ee74c1cb493cee0d5998b895b1c79bVladislav Kaznacheev    }
528d03a495b04ee74c1cb493cee0d5998b895b1c79bVladislav Kaznacheev
529d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
530d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean isRunning() {
5311e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        return (!mPendingAdditions.isEmpty()
5321e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || !mPendingChanges.isEmpty()
5331e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || !mPendingMoves.isEmpty()
5341e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || !mPendingRemovals.isEmpty()
5351e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || !mMoveAnimations.isEmpty()
5361e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || !mRemoveAnimations.isEmpty()
5371e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || !mAddAnimations.isEmpty()
5381e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || !mChangeAnimations.isEmpty()
5391e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || !mMovesList.isEmpty()
5401e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || !mAdditionsList.isEmpty()
5411e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || !mChangesList.isEmpty());
542d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
543d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
544d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    /**
545d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     * Check the state of currently pending and running animations. If there are none
546d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     * pending/running, call {@link #dispatchAnimationsFinished()} to notify any
547d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     * listeners.
548d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     */
5493a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    void dispatchFinishedWhenDone() {
550d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (!isRunning()) {
551d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchAnimationsFinished();
552d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
553d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
554d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
555d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
556d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void endAnimations() {
55793b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        int count = mPendingMoves.size();
55893b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        for (int i = count - 1; i >= 0; i--) {
55993b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            MoveInfo item = mPendingMoves.get(i);
56093b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            View view = item.holder.itemView;
561ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            view.setTranslationY(0);
562ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            view.setTranslationX(0);
56393b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            dispatchMoveFinished(item.holder);
564ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu            mPendingMoves.remove(i);
56593b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        }
56693b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        count = mPendingRemovals.size();
56793b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        for (int i = count - 1; i >= 0; i--) {
56893b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            ViewHolder item = mPendingRemovals.get(i);
56993b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            dispatchRemoveFinished(item);
570ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu            mPendingRemovals.remove(i);
57193b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        }
57293b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        count = mPendingAdditions.size();
57393b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        for (int i = count - 1; i >= 0; i--) {
57493b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            ViewHolder item = mPendingAdditions.get(i);
575ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            item.itemView.setAlpha(1);
57693b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            dispatchAddFinished(item);
577ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu            mPendingAdditions.remove(i);
57893b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        }
579235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        count = mPendingChanges.size();
580235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        for (int i = count - 1; i >= 0; i--) {
581a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            endChangeAnimationIfNecessary(mPendingChanges.get(i));
582235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
583a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        mPendingChanges.clear();
584d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (!isRunning()) {
585d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            return;
586d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
587235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase
5880e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        int listCount = mMovesList.size();
5890e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = listCount - 1; i >= 0; i--) {
5900e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<MoveInfo> moves = mMovesList.get(i);
5910e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            count = moves.size();
5920e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            for (int j = count - 1; j >= 0; j--) {
5930e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                MoveInfo moveInfo = moves.get(j);
5940e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                ViewHolder item = moveInfo.holder;
5950e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                View view = item.itemView;
596ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                view.setTranslationY(0);
597ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                view.setTranslationX(0);
5980e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                dispatchMoveFinished(moveInfo.holder);
5990e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                moves.remove(j);
6000e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                if (moves.isEmpty()) {
6010e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mMovesList.remove(moves);
6020e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                }
6030e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            }
604235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
6050e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        listCount = mAdditionsList.size();
6060e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = listCount - 1; i >= 0; i--) {
6070e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<ViewHolder> additions = mAdditionsList.get(i);
6080e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            count = additions.size();
6090e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            for (int j = count - 1; j >= 0; j--) {
6100e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                ViewHolder item = additions.get(j);
6110e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                View view = item.itemView;
612ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas                view.setAlpha(1);
6130e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                dispatchAddFinished(item);
6140e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                additions.remove(j);
6150e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                if (additions.isEmpty()) {
6160e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mAdditionsList.remove(additions);
6170e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                }
6180e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            }
619235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
6200e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        listCount = mChangesList.size();
6210e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = listCount - 1; i >= 0; i--) {
6220e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<ChangeInfo> changes = mChangesList.get(i);
6230e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            count = changes.size();
6240e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            for (int j = count - 1; j >= 0; j--) {
6250e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                endChangeAnimationIfNecessary(changes.get(j));
6260e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                if (changes.isEmpty()) {
6270e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mChangesList.remove(changes);
6280e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                }
6290e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            }
630235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
631235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase
632a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        cancelAll(mRemoveAnimations);
633a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        cancelAll(mMoveAnimations);
634a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        cancelAll(mAddAnimations);
635a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        cancelAll(mChangeAnimations);
636ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu
637d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        dispatchAnimationsFinished();
638d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
639d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
640a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    void cancelAll(List<ViewHolder> viewHolders) {
641a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        for (int i = viewHolders.size() - 1; i >= 0; i--) {
642ca03208c6ef5bd79af99309d0e14db4a238cb691Aurimas Liutikas            viewHolders.get(i).itemView.animate().cancel();
643a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
644a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    }
645a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
646abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar    /**
647abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * {@inheritDoc}
648abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * <p>
649abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * If the payload list is not empty, DefaultItemAnimator returns <code>true</code>.
650abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * When this is the case:
651abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * <ul>
652abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * <li>If you override {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, both
653abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * ViewHolder arguments will be the same instance.
654abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * </li>
655abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * <li>
656abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * If you are not overriding {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)},
657abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * then DefaultItemAnimator will call {@link #animateMove(ViewHolder, int, int, int, int)} and
658abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * run a move animation instead.
659abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * </li>
660abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     * </ul>
661abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar     */
662abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar    @Override
663abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar    public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder,
664abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar            @NonNull List<Object> payloads) {
665abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar        return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
666abea494886a17e7a51080ab5e9c2ca041c533353Yigit Boyar    }
667d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase}
668