18ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar/*
28ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Copyright (C) 2014 The Android Open Source Project
38ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar *
48ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
58ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * you may not use this file except in compliance with the License.
68ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * You may obtain a copy of the License at
78ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar *
88ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
98ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar *
108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Unless required by applicable law or agreed to in writing, software
118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * See the License for the specific language governing permissions and
148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * limitations under the License.
158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */
168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarpackage android.support.v7.widget;
188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport android.support.v4.util.Pools;
201faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyarimport android.util.Log;
218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.ArrayList;
238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.Collections;
248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.List;
258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport static android.support.v7.widget.RecyclerView.*;
278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar/**
298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Helper class that can enqueue and process adapter update operations.
308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * <p>
318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * To support animations, RecyclerView presents an older version the Adapter to best represent
328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * previous state of the layout. Sometimes, this is not trivial when items are removed that were
338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * not laid out, in which case, RecyclerView has no way of providing that item's view for
348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * animations.
358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * <p>
368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * AdapterHelper creates an UpdateOp for each adapter data change then pre-processes them. During
378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * pre processing, AdapterHelper finds out which UpdateOps can be deferred to second layout pass
388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * and which cannot. For the UpdateOps that cannot be deferred, AdapterHelper will change them
398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * according to previously deferred operation and dispatch them before the first layout pass. It
408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * also takes care of updating deferred UpdateOps since order of operations is changed by this
418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * process.
428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * <p>
438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * Although operations may be forwarded to LayoutManager in different orders, resulting data set
448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar * is guaranteed to be the consistent.
458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar */
464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarclass AdapterHelper implements OpReorderer.Callback {
478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    final static int POSITION_TYPE_INVISIBLE = 0;
498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    final static int POSITION_TYPE_NEW_OR_LAID_OUT = 1;
518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
521faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar    private static final boolean DEBUG = false;
531faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar
541faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar    private static final String TAG = "AHT";
551faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar
568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    private Pools.Pool<UpdateOp> mUpdateOpPool = new Pools.SimplePool<UpdateOp>(UpdateOp.POOL_SIZE);
578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    final ArrayList<UpdateOp> mPendingUpdates = new ArrayList<UpdateOp>();
598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    final ArrayList<UpdateOp> mPostponedList = new ArrayList<UpdateOp>();
618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    final Callback mCallback;
638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    Runnable mOnItemProcessedCallback;
658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    final boolean mDisableRecycler;
678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    final OpReorderer mOpReorderer;
694b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
70121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    private int mExistingUpdateTypes = 0;
71121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    AdapterHelper(Callback callback) {
738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        this(callback, false);
748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    AdapterHelper(Callback callback, boolean disableRecycler) {
778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mCallback = callback;
788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mDisableRecycler = disableRecycler;
794b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mOpReorderer = new OpReorderer(this);
808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    AdapterHelper addUpdateOp(UpdateOp... ops) {
838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        Collections.addAll(mPendingUpdates, ops);
848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return this;
858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    void reset() {
888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        recycleUpdateOpsAndClearList(mPendingUpdates);
898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        recycleUpdateOpsAndClearList(mPostponedList);
90121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mExistingUpdateTypes = 0;
918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    void preProcess() {
944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mOpReorderer.reorderOps(mPendingUpdates);
958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        final int count = mPendingUpdates.size();
968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < count; i++) {
978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            UpdateOp op = mPendingUpdates.get(i);
988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            switch (op.cmd) {
998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                case UpdateOp.ADD:
1008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    applyAdd(op);
1018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    break;
1028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                case UpdateOp.REMOVE:
1038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    applyRemove(op);
1048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    break;
1058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                case UpdateOp.UPDATE:
1068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    applyUpdate(op);
1078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    break;
1081faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                case UpdateOp.MOVE:
1091faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    applyMove(op);
1101faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    break;
1118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
1128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (mOnItemProcessedCallback != null) {
1138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mOnItemProcessedCallback.run();
1148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
1158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
1168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mPendingUpdates.clear();
1178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
1188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
1198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    void consumePostponedUpdates() {
1208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        final int count = mPostponedList.size();
1218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < count; i++) {
1228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mCallback.onDispatchSecondPass(mPostponedList.get(i));
1238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
1248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        recycleUpdateOpsAndClearList(mPostponedList);
125121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mExistingUpdateTypes = 0;
1268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
1278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
1281faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar    private void applyMove(UpdateOp op) {
1291faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        // MOVE ops are pre-processed so at this point, we know that item is still in the adapter.
1301faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        // otherwise, it would be converted into a REMOVE operation
1314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        postponeAndUpdateViewHolders(op);
1321faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar    }
1331faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar
1348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    private void applyRemove(UpdateOp op) {
1358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int tmpStart = op.positionStart;
1368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int tmpCount = 0;
1378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int tmpEnd = op.positionStart + op.itemCount;
1388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int type = -1;
1398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int position = op.positionStart; position < tmpEnd; position++) {
1408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            boolean typeChanged = false;
1418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            ViewHolder vh = mCallback.findViewHolder(position);
1421faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            if (vh != null || canFindInPreLayout(position)) {
1438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // If a ViewHolder exists or this is a newly added item, we can defer this update
1448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // to post layout stage.
1458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // * For existing ViewHolders, we'll fake its existence in the pre-layout phase.
1468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // * For items that are added and removed in the same process cycle, they won't
1478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // have any effect in pre-layout since their add ops are already deferred to
1488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // post-layout pass.
1498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                if (type == POSITION_TYPE_INVISIBLE) {
1508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    // Looks like we have other updates that we cannot merge with this one.
1518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    // Create an UpdateOp and dispatch it to LayoutManager.
15221b345f101abc385496f42d250e580d21f1287b6Dake Gu                    UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null);
1534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    dispatchAndUpdateViewHolders(newOp);
1548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    typeChanged = true;
1558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
1568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                type = POSITION_TYPE_NEW_OR_LAID_OUT;
1578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            } else {
1588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // This update cannot be recovered because we don't have a ViewHolder representing
1598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // this position. Instead, post it to LayoutManager immediately
1608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                if (type == POSITION_TYPE_NEW_OR_LAID_OUT) {
1618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    // Looks like we have other updates that we cannot merge with this one.
1628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    // Create UpdateOp op and dispatch it to LayoutManager.
16321b345f101abc385496f42d250e580d21f1287b6Dake Gu                    UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null);
1644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    postponeAndUpdateViewHolders(newOp);
1658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    typeChanged = true;
1668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
1678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                type = POSITION_TYPE_INVISIBLE;
1688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
1698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (typeChanged) {
1708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                position -= tmpCount; // also equal to tmpStart
1718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                tmpEnd -= tmpCount;
1728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                tmpCount = 1;
1738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            } else {
1748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                tmpCount++;
1758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
1768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
1778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        if (tmpCount != op.itemCount) { // all 1 effect
1788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            recycleUpdateOp(op);
17921b345f101abc385496f42d250e580d21f1287b6Dake Gu            op = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null);
1808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
1818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        if (type == POSITION_TYPE_INVISIBLE) {
1824b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            dispatchAndUpdateViewHolders(op);
1838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        } else {
1844b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            postponeAndUpdateViewHolders(op);
1858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
1868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
1878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
1888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    private void applyUpdate(UpdateOp op) {
1898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int tmpStart = op.positionStart;
1908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int tmpCount = 0;
1918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int tmpEnd = op.positionStart + op.itemCount;
1928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int type = -1;
1938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int position = op.positionStart; position < tmpEnd; position++) {
1948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            ViewHolder vh = mCallback.findViewHolder(position);
1951faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            if (vh != null || canFindInPreLayout(position)) { // deferred
1968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                if (type == POSITION_TYPE_INVISIBLE) {
19721b345f101abc385496f42d250e580d21f1287b6Dake Gu                    UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount,
19821b345f101abc385496f42d250e580d21f1287b6Dake Gu                            op.payload);
1994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    dispatchAndUpdateViewHolders(newOp);
2008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    tmpCount = 0;
201e4fde6825bba479c9b030feb8f810694d46b2f06Yigit Boyar                    tmpStart = position;
2028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
2038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                type = POSITION_TYPE_NEW_OR_LAID_OUT;
2048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            } else { // applied
2058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                if (type == POSITION_TYPE_NEW_OR_LAID_OUT) {
20621b345f101abc385496f42d250e580d21f1287b6Dake Gu                    UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount,
20721b345f101abc385496f42d250e580d21f1287b6Dake Gu                            op.payload);
2084b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    postponeAndUpdateViewHolders(newOp);
2098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    tmpCount = 0;
210e4fde6825bba479c9b030feb8f810694d46b2f06Yigit Boyar                    tmpStart = position;
2118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
2128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                type = POSITION_TYPE_INVISIBLE;
2138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
2148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            tmpCount++;
2158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
2168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        if (tmpCount != op.itemCount) { // all 1 effect
21721b345f101abc385496f42d250e580d21f1287b6Dake Gu            Object payload = op.payload;
2188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            recycleUpdateOp(op);
21921b345f101abc385496f42d250e580d21f1287b6Dake Gu            op = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, payload);
2208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
2218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        if (type == POSITION_TYPE_INVISIBLE) {
2224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            dispatchAndUpdateViewHolders(op);
2238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        } else {
2244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            postponeAndUpdateViewHolders(op);
2258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
2268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
2278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
2284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void dispatchAndUpdateViewHolders(UpdateOp op) {
2298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // tricky part.
2308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // traverse all postpones and revert their changes on this op if necessary, apply updated
2318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // dispatch to them since now they are after this op.
2321faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        if (op.cmd == UpdateOp.ADD || op.cmd == UpdateOp.MOVE) {
2331faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            throw new IllegalArgumentException("should not dispatch add or move for pre layout");
2341faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        }
2351faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        if (DEBUG) {
2364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            Log.d(TAG, "dispatch (pre)" + op);
2371faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            Log.d(TAG, "postponed state before:");
2381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            for (UpdateOp updateOp : mPostponedList) {
2391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                Log.d(TAG, updateOp.toString());
2401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            }
2411faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            Log.d(TAG, "----");
2421faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        }
2431faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar
2441faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        // handle each pos 1 by 1 to ensure continuity. If it breaks, dispatch partial
2454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // TODO Since move ops are pushed to end, we should not need this anymore
2461faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        int tmpStart = updatePositionWithPostponed(op.positionStart, op.cmd);
2471faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        if (DEBUG) {
2481faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            Log.d(TAG, "pos:" + op.positionStart + ",updatedPos:" + tmpStart);
2491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        }
2501faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        int tmpCnt = 1;
2514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        int offsetPositionForPartial = op.positionStart;
2524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        final int positionMultiplier;
2534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        switch (op.cmd) {
2544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case UpdateOp.UPDATE:
2554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                positionMultiplier = 1;
2564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
2574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case UpdateOp.REMOVE:
2584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                positionMultiplier = 0;
2594b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
2604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            default:
2614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                throw new IllegalArgumentException("op should be remove or update." + op);
2624b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2631faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        for (int p = 1; p < op.itemCount; p++) {
2644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            final int pos = op.positionStart + (positionMultiplier * p);
2651faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            int updatedPos = updatePositionWithPostponed(pos, op.cmd);
2661faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            if (DEBUG) {
2671faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                Log.d(TAG, "pos:" + pos + ",updatedPos:" + updatedPos);
2681faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            }
2691faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            boolean continuous = false;
2701faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            switch (op.cmd) {
2711faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                case UpdateOp.UPDATE:
2721faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    continuous = updatedPos == tmpStart + 1;
2731faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    break;
2741faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                case UpdateOp.REMOVE:
2751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    continuous = updatedPos == tmpStart;
2761faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    break;
2771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            }
2781faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            if (continuous) {
2791faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                tmpCnt++;
2801faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            } else {
2811faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                // need to dispatch this separately
28221b345f101abc385496f42d250e580d21f1287b6Dake Gu                UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, op.payload);
2831faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                if (DEBUG) {
2841faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    Log.d(TAG, "need to dispatch separately " + tmp);
2851faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                }
2864b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial);
2871faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                recycleUpdateOp(tmp);
2884b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (op.cmd == UpdateOp.UPDATE) {
2894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    offsetPositionForPartial += tmpCnt;
2904b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
2911faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                tmpStart = updatedPos;// need to remove previously dispatched
2921faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                tmpCnt = 1;
2931faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            }
2941faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        }
29521b345f101abc385496f42d250e580d21f1287b6Dake Gu        Object payload = op.payload;
2961faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        recycleUpdateOp(op);
2971faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        if (tmpCnt > 0) {
29821b345f101abc385496f42d250e580d21f1287b6Dake Gu            UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, payload);
2991faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            if (DEBUG) {
3001faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                Log.d(TAG, "dispatching:" + tmp);
3011faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            }
3024b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial);
3031faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            recycleUpdateOp(tmp);
3041faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        }
3051faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        if (DEBUG) {
3061faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            Log.d(TAG, "post dispatch");
3071faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            Log.d(TAG, "postponed state after:");
3081faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            for (UpdateOp updateOp : mPostponedList) {
3091faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                Log.d(TAG, updateOp.toString());
3101faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            }
3111faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            Log.d(TAG, "----");
3121faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        }
3131faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar    }
3141faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar
3154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    void dispatchFirstPassAndUpdateViewHolders(UpdateOp op, int offsetStart) {
3164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mCallback.onDispatchFirstPass(op);
3174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        switch (op.cmd) {
3184b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case UpdateOp.REMOVE:
3194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                mCallback.offsetPositionsForRemovingInvisible(offsetStart, op.itemCount);
3204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
3214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case UpdateOp.UPDATE:
32221b345f101abc385496f42d250e580d21f1287b6Dake Gu                mCallback.markViewHoldersUpdated(offsetStart, op.itemCount, op.payload);
3234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
3244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            default:
3254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                throw new IllegalArgumentException("only remove and update ops can be dispatched"
3264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                        + " in first pass");
3274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
3284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
3294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3301faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar    private int updatePositionWithPostponed(int pos, int cmd) {
3318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        final int count = mPostponedList.size();
3328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = count - 1; i >= 0; i--) {
3338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            UpdateOp postponed = mPostponedList.get(i);
3341faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            if (postponed.cmd == UpdateOp.MOVE) {
3351faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                int start, end;
3361faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                if (postponed.positionStart < postponed.itemCount) {
3371faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    start = postponed.positionStart;
3381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    end = postponed.itemCount;
3391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                } else {
3401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    start = postponed.itemCount;
3411faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    end = postponed.positionStart;
3421faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                }
3431faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                if (pos >= start && pos <= end) {
3441faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    //i'm affected
3451faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    if (start == postponed.positionStart) {
3461faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        if (cmd == UpdateOp.ADD) {
3471faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                            postponed.itemCount++;
3481faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        } else if (cmd == UpdateOp.REMOVE) {
3491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                            postponed.itemCount--;
3501faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        }
3511faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        // op moved to left, move it right to revert
3521faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        pos++;
3531faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    } else {
3541faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        if (cmd == UpdateOp.ADD) {
3551faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                            postponed.positionStart++;
3561faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        } else if (cmd == UpdateOp.REMOVE) {
3571faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                            postponed.positionStart--;
3581faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        }
3591faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        // op was moved right, move left to revert
3601faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        pos--;
3611faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    }
3621faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                } else if (pos < postponed.positionStart) {
3631faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    // postponed MV is outside the dispatched OP. if it is before, offset
3641faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    if (cmd == UpdateOp.ADD) {
3651faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        postponed.positionStart++;
3661faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        postponed.itemCount++;
3671faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    } else if (cmd == UpdateOp.REMOVE) {
3681faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        postponed.positionStart--;
3691faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        postponed.itemCount--;
3701faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    }
3711faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                }
3728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            } else {
3731faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                if (postponed.positionStart <= pos) {
3741faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    if (postponed.cmd == UpdateOp.ADD) {
3751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        pos -= postponed.itemCount;
3761faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    } else if (postponed.cmd == UpdateOp.REMOVE) {
3771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        pos += postponed.itemCount;
3781faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    }
3791faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                } else {
3801faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    if (cmd == UpdateOp.ADD) {
3811faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        postponed.positionStart++;
3821faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    } else if (cmd == UpdateOp.REMOVE) {
3831faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        postponed.positionStart--;
3841faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    }
3851faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                }
3861faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            }
3871faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            if (DEBUG) {
3881faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                Log.d(TAG, "dispath (step" + i + ")");
3891faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                Log.d(TAG, "postponed state:" + i + ", pos:" + pos);
3901faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                for (UpdateOp updateOp : mPostponedList) {
3911faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    Log.d(TAG, updateOp.toString());
3921faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                }
3931faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                Log.d(TAG, "----");
3948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
3958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
3961faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        for (int i = mPostponedList.size() - 1; i >= 0; i--) {
3971faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            UpdateOp op = mPostponedList.get(i);
3981faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            if (op.cmd == UpdateOp.MOVE) {
3991faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                if (op.itemCount == op.positionStart || op.itemCount < 0) {
4001faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    mPostponedList.remove(i);
4011faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    recycleUpdateOp(op);
4021faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                }
4031faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            } else if (op.itemCount <= 0) {
4041faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                mPostponedList.remove(i);
4051faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                recycleUpdateOp(op);
4061faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            }
4071faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        }
4081faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        return pos;
4098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
4111faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar    private boolean canFindInPreLayout(int position) {
4128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        final int count = mPostponedList.size();
4138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < count; i++) {
4148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            UpdateOp op = mPostponedList.get(i);
4151faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            if (op.cmd == UpdateOp.MOVE) {
4164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (findPositionOffset(op.itemCount, i + 1) == position) {
4171faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    return true;
4181faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                }
4191faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            } else if (op.cmd == UpdateOp.ADD) {
4201faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                // TODO optimize.
4211faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                final int end = op.positionStart + op.itemCount;
4221faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                for (int pos = op.positionStart; pos < end; pos++) {
4231faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    if (findPositionOffset(pos, i + 1) == position) {
4241faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                        return true;
4251faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    }
4261faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                }
4278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
4288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
4298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return false;
4308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
4328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    private void applyAdd(UpdateOp op) {
4334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        postponeAndUpdateViewHolders(op);
4348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
4364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void postponeAndUpdateViewHolders(UpdateOp op) {
4371faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        if (DEBUG) {
4381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            Log.d(TAG, "postponing " + op);
4391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        }
4408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mPostponedList.add(op);
4414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        switch (op.cmd) {
4424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case UpdateOp.ADD:
4434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount);
4444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
4454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case UpdateOp.MOVE:
4464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                mCallback.offsetPositionsForMove(op.positionStart, op.itemCount);
4474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
4484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case UpdateOp.REMOVE:
4494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                mCallback.offsetPositionsForRemovingLaidOutOrNewView(op.positionStart,
4504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                        op.itemCount);
4514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
4524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case UpdateOp.UPDATE:
45321b345f101abc385496f42d250e580d21f1287b6Dake Gu                mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload);
4544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
4554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            default:
4564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                throw new IllegalArgumentException("Unknown update op type for " + op);
4574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
4588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
4608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    boolean hasPendingUpdates() {
4618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return mPendingUpdates.size() > 0;
4628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
464121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    boolean hasAnyUpdateTypes(int updateTypes) {
465121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        return (mExistingUpdateTypes & updateTypes) != 0;
466121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
467121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
4688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    int findPositionOffset(int position) {
4698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return findPositionOffset(position, 0);
4708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
472668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar    int findPositionOffset(int position, int firstPostponedItem) {
4738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int count = mPostponedList.size();
474668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar        for (int i = firstPostponedItem; i < count; ++i) {
4758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            UpdateOp op = mPostponedList.get(i);
4761faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            if (op.cmd == UpdateOp.MOVE) {
4771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                if (op.positionStart == position) {
4781faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    position = op.itemCount;
4794bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar                } else {
4804bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar                    if (op.positionStart < position) {
4814bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar                        position--; // like a remove
4824bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar                    }
4834bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar                    if (op.itemCount <= position) {
4844bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar                        position++; // like an add
4854bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar                    }
4861faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                }
4871faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            } else if (op.positionStart <= position) {
4888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                if (op.cmd == UpdateOp.REMOVE) {
4894bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar                    if (position < op.positionStart + op.itemCount) {
4904bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar                        return -1;
4914bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar                    }
4921faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    position -= op.itemCount;
4938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                } else if (op.cmd == UpdateOp.ADD) {
4941faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    position += op.itemCount;
4958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
4968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
4978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
4981faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        return position;
4998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
5008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
5018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    /**
5028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     * @return True if updates should be processed.
5038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     */
50421b345f101abc385496f42d250e580d21f1287b6Dake Gu    boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) {
5058fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        if (itemCount < 1) {
5068fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            return false;
5078fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        }
50821b345f101abc385496f42d250e580d21f1287b6Dake Gu        mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload));
509121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mExistingUpdateTypes |= UpdateOp.UPDATE;
5108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return mPendingUpdates.size() == 1;
5118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
5128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
5138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    /**
5148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     * @return True if updates should be processed.
5158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     */
5168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    boolean onItemRangeInserted(int positionStart, int itemCount) {
5178fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        if (itemCount < 1) {
5188fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            return false;
5198fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        }
52021b345f101abc385496f42d250e580d21f1287b6Dake Gu        mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null));
521121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mExistingUpdateTypes |= UpdateOp.ADD;
5228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return mPendingUpdates.size() == 1;
5238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
5248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
5258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    /**
5268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     * @return True if updates should be processed.
5278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     */
5288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    boolean onItemRangeRemoved(int positionStart, int itemCount) {
5298fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        if (itemCount < 1) {
5308fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            return false;
5318fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        }
53221b345f101abc385496f42d250e580d21f1287b6Dake Gu        mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null));
533121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mExistingUpdateTypes |= UpdateOp.REMOVE;
5348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return mPendingUpdates.size() == 1;
5358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
5368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
5378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    /**
5381faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar     * @return True if updates should be processed.
5391faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar     */
5401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar    boolean onItemRangeMoved(int from, int to, int itemCount) {
5411faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        if (from == to) {
5424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return false; // no-op
5431faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        }
5441faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        if (itemCount != 1) {
5451faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar            throw new IllegalArgumentException("Moving more than 1 item is not supported yet");
5461faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        }
54721b345f101abc385496f42d250e580d21f1287b6Dake Gu        mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null));
548121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mExistingUpdateTypes |= UpdateOp.MOVE;
5491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        return mPendingUpdates.size() == 1;
5501faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar    }
5511faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar
5521faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar    /**
5538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     * Skips pre-processing and applies all updates in one pass.
5548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     */
5558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    void consumeUpdatesInOnePass() {
5568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // we still consume postponed updates (if there is) in case there was a pre-process call
5578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // w/o a matching consumePostponedUpdates.
5588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        consumePostponedUpdates();
5598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        final int count = mPendingUpdates.size();
5608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < count; i++) {
5618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            UpdateOp op = mPendingUpdates.get(i);
5628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            switch (op.cmd) {
5638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                case UpdateOp.ADD:
5648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    mCallback.onDispatchSecondPass(op);
56516e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar                    mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount);
5668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    break;
5678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                case UpdateOp.REMOVE:
5688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    mCallback.onDispatchSecondPass(op);
56916e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar                    mCallback.offsetPositionsForRemovingInvisible(op.positionStart, op.itemCount);
5708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    break;
5718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                case UpdateOp.UPDATE:
57216e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar                    mCallback.onDispatchSecondPass(op);
57321b345f101abc385496f42d250e580d21f1287b6Dake Gu                    mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload);
5748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    break;
5751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                case UpdateOp.MOVE:
57616e5adf5416248d97f2aeaa9d5e17bb5093130ebYigit Boyar                    mCallback.onDispatchSecondPass(op);
5771faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    mCallback.offsetPositionsForMove(op.positionStart, op.itemCount);
5781faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    break;
5798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
5808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (mOnItemProcessedCallback != null) {
5818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mOnItemProcessedCallback.run();
5828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
5838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
5848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        recycleUpdateOpsAndClearList(mPendingUpdates);
585121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mExistingUpdateTypes = 0;
5868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
5878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
588115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    public int applyPendingUpdatesToPosition(int position) {
589115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        final int size = mPendingUpdates.size();
590115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        for (int i = 0; i < size; i ++) {
591115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            UpdateOp op = mPendingUpdates.get(i);
592115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            switch (op.cmd) {
593115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                case UpdateOp.ADD:
594115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    if (op.positionStart <= position) {
595115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        position += op.itemCount;
596115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    }
597115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    break;
598115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                case UpdateOp.REMOVE:
599115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    if (op.positionStart <= position) {
600115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        final int end = op.positionStart + op.itemCount;
601115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        if (end > position) {
602115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            return RecyclerView.NO_POSITION;
603115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        }
604115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        position -= op.itemCount;
605115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    }
606115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    break;
607115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                case UpdateOp.MOVE:
608115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    if (op.positionStart == position) {
609115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        position = op.itemCount;//position end
610115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    } else {
611115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        if (op.positionStart < position) {
612115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            position -= 1;
613115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        }
614115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        if (op.itemCount <= position) {
615115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            position += 1;
616115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        }
617115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    }
618115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    break;
619115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
620115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        }
621115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        return position;
622115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
623115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
6244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    boolean hasUpdates() {
6254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        return !mPostponedList.isEmpty() && !mPendingUpdates.isEmpty();
6264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
6274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
6288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    /**
6298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     * Queued operation to happen when child views are updated.
6308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     */
6318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    static class UpdateOp {
6328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
633121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        static final int ADD = 1;
6348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
635121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        static final int REMOVE = 1 << 1;
6368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
637121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        static final int UPDATE = 1 << 2;
6388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
639121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        static final int MOVE = 1 << 3;
6401faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar
6418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        static final int POOL_SIZE = 30;
6428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
6438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int cmd;
6448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
6458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int positionStart;
6468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
64721b345f101abc385496f42d250e580d21f1287b6Dake Gu        Object payload;
64821b345f101abc385496f42d250e580d21f1287b6Dake Gu
6491faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        // holds the target position if this is a MOVE
6508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int itemCount;
6518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
65221b345f101abc385496f42d250e580d21f1287b6Dake Gu        UpdateOp(int cmd, int positionStart, int itemCount, Object payload) {
6538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            this.cmd = cmd;
6548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            this.positionStart = positionStart;
6558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            this.itemCount = itemCount;
65621b345f101abc385496f42d250e580d21f1287b6Dake Gu            this.payload = payload;
6578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
6588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
6598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        String cmdToString() {
6608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            switch (cmd) {
6618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                case ADD:
6628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    return "add";
6638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                case REMOVE:
6648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    return "rm";
6658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                case UPDATE:
6668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    return "up";
6671faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                case MOVE:
6681faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar                    return "mv";
6698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
6708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return "??";
6718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
6728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
6738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        @Override
6748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public String toString() {
67521b345f101abc385496f42d250e580d21f1287b6Dake Gu            return Integer.toHexString(System.identityHashCode(this))
67621b345f101abc385496f42d250e580d21f1287b6Dake Gu                    + "[" + cmdToString() + ",s:" + positionStart + "c:" + itemCount
67721b345f101abc385496f42d250e580d21f1287b6Dake Gu                    +",p:"+payload + "]";
6788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
6798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
6808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        @Override
6818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public boolean equals(Object o) {
6828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (this == o) {
6838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                return true;
6848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
6858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (o == null || getClass() != o.getClass()) {
6868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                return false;
6878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
6888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
6898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            UpdateOp op = (UpdateOp) o;
6908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
6918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (cmd != op.cmd) {
6928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                return false;
6938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
6944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (cmd == MOVE && Math.abs(itemCount - positionStart) == 1) {
6954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                // reverse of this is also true
6964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (itemCount == op.positionStart && positionStart == op.itemCount) {
6974b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    return true;
6984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
6994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
7008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (itemCount != op.itemCount) {
7018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                return false;
7028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
7038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (positionStart != op.positionStart) {
7048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                return false;
7058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
70621b345f101abc385496f42d250e580d21f1287b6Dake Gu            if (payload != null) {
70721b345f101abc385496f42d250e580d21f1287b6Dake Gu                if (!payload.equals(op.payload)) {
70821b345f101abc385496f42d250e580d21f1287b6Dake Gu                    return false;
70921b345f101abc385496f42d250e580d21f1287b6Dake Gu                }
71021b345f101abc385496f42d250e580d21f1287b6Dake Gu            } else if (op.payload != null) {
71121b345f101abc385496f42d250e580d21f1287b6Dake Gu                return false;
71221b345f101abc385496f42d250e580d21f1287b6Dake Gu            }
7138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return true;
7158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
7168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        @Override
7188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public int hashCode() {
7198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            int result = cmd;
7208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            result = 31 * result + positionStart;
7218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            result = 31 * result + itemCount;
7228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return result;
7238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
7248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
7258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    @Override
72721b345f101abc385496f42d250e580d21f1287b6Dake Gu    public UpdateOp obtainUpdateOp(int cmd, int positionStart, int itemCount, Object payload) {
7288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        UpdateOp op = mUpdateOpPool.acquire();
7298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        if (op == null) {
73021b345f101abc385496f42d250e580d21f1287b6Dake Gu            op = new UpdateOp(cmd, positionStart, itemCount, payload);
7318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        } else {
7328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            op.cmd = cmd;
7338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            op.positionStart = positionStart;
7348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            op.itemCount = itemCount;
73521b345f101abc385496f42d250e580d21f1287b6Dake Gu            op.payload = payload;
7368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
7378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return op;
7388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
7398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    @Override
7414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void recycleUpdateOp(UpdateOp op) {
7428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        if (!mDisableRecycler) {
74321b345f101abc385496f42d250e580d21f1287b6Dake Gu            op.payload = null;
7448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mUpdateOpPool.release(op);
7458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
7468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
7478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    void recycleUpdateOpsAndClearList(List<UpdateOp> ops) {
7498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        final int count = ops.size();
7508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < count; i++) {
7518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            recycleUpdateOp(ops.get(i));
7528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
7538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        ops.clear();
7548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
7558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    /**
7578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     * Contract between AdapterHelper and RecyclerView.
7588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar     */
7598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    static interface Callback {
7608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        ViewHolder findViewHolder(int position);
7628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        void offsetPositionsForRemovingInvisible(int positionStart, int itemCount);
7648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        void offsetPositionsForRemovingLaidOutOrNewView(int positionStart, int itemCount);
7668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
76721b345f101abc385496f42d250e580d21f1287b6Dake Gu        void markViewHoldersUpdated(int positionStart, int itemCount, Object payloads);
7688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        void onDispatchFirstPass(UpdateOp updateOp);
7708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        void onDispatchSecondPass(UpdateOp updateOp);
7728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
7738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        void offsetPositionsForAdd(int positionStart, int itemCount);
7741faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar
7751faed0c7c20fc3a0b7befabbac1beac1019effc7Yigit Boyar        void offsetPositionsForMove(int from, int to);
7768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
7774bacf13ec17763ba2e2d049d32a4a1dcca77a433Yigit Boyar}
778