Prioritize delete animation over move animation

RecyclerView was running a move animation when an item
is deleted but also moved. We should run delete animation
instead to make sure proper callbacks arrive.

In the future, this can be changed but for now, it is not
LayoutManager's responsibility to move a deleted item so
occurrences of a "deleted item being moved" can be ignored.

Bug: 21639668
Change-Id: I5b1cfa37a7e5e7a2ef34d7cc76fbebc41907cf9a
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index c479033..74c8b58 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -2916,7 +2916,7 @@
         int oldTop = disappearingItem.top;
         int newLeft = disappearingItemView.getLeft();
         int newTop = disappearingItemView.getTop();
-        if (oldLeft != newLeft || oldTop != newTop) {
+        if (!disappearingItem.holder.isRemoved() && (oldLeft != newLeft || oldTop != newTop)) {
             disappearingItem.holder.setIsRecyclable(false);
             disappearingItemView.layout(newLeft, newTop,
                     newLeft + disappearingItemView.getWidth(),
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
index 45fa6eb..a79f863 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -212,6 +212,7 @@
                     }
                 });
         if (running) {
+            latch.countDown();
             latch.await(seconds, TimeUnit.SECONDS);
         }
     }
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
index f9e3d0c..469c794 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Rect;
 import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -111,6 +112,52 @@
         assertFalse("there should not be any animations running", animator.isRunning());
     }
 
+    public void testMoveDeleted() throws Throwable {
+        setupBasic(4, 0, 3);
+        waitForAnimations(2);
+        final View[] targetChild = new View[1];
+        final LoggingItemAnimator animator = new LoggingItemAnimator();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.setItemAnimator(animator);
+                targetChild[0] = mRecyclerView.getChildAt(1);
+            }
+        });
+
+        assertNotNull("test sanity", targetChild);
+        mLayoutManager.expectLayouts(1);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
+                    @Override
+                    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                            RecyclerView.State state) {
+                        if (view == targetChild[0]) {
+                            outRect.set(10, 20, 30, 40);
+                        } else {
+                            outRect.set(0, 0, 0, 0);
+                        }
+                    }
+                });
+            }
+        });
+        mLayoutManager.waitForLayout(1);
+
+        // now delete that item.
+        mLayoutManager.expectLayouts(2);
+        RecyclerView.ViewHolder targetVH = mRecyclerView.getChildViewHolder(targetChild[0]);
+        targetChild[0] = null;
+        mTestAdapter.deleteAndNotify(1, 1);
+        mLayoutManager.waitForLayout(2);
+        assertFalse("if deleted view moves, it should not be in move animations",
+                animator.mMoveVHs.contains(targetVH));
+        assertEquals("only 1 item is deleted", 1, animator.mRemoveVHs.size());
+        assertTrue("the target view is removed", animator.mRemoveVHs.contains(targetVH
+        ));
+    }
+
     public void testPreLayoutPositionCleanup() throws Throwable {
         setupBasic(4, 0, 4);
         mLayoutManager.expectLayouts(2);