recyclerview: fix getViewForPosition crash in onMeasure()

LM.onMeasure() might be called twice before onLayout() if
1. supportsPredictive is true
2. autoMeasureEnabled is false
3. hasFixedSize is false
4. RV is a child of LinearLayout, layout_width is match_parent.

In the second LM.onMeasure() call, if LM uses getViewForPosition().
It will crash. Looks like RV is expecting onMeasure() being called
only once before onLayout(), this CL address this bypassing the
second LM.onMeasure() call.

Test: preditiveMeasuredCrashTest
Bug: 63142268
Change-Id: I2c5b983270ed4d633a3cf1fcd2676d729e4ed31b
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index 8033400..33c706f 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -3144,6 +3144,14 @@
                 }
                 mAdapterUpdateDuringMeasure = false;
                 resumeRequestLayout(false);
+            } else if (mState.mRunPredictiveAnimations) {
+                // If mAdapterUpdateDuringMeasure is false and mRunPredictiveAnimations is true:
+                // this means there is already an onMeasure() call performed to handle the pending
+                // adapter change, two onMeasure() calls can happen if RV is a child of LinearLayout
+                // with layout_width=MATCH_PARENT. RV cannot call LM.onMeasure() second time
+                // because getViewForPosition() will crash when LM uses a child to measure.
+                defaultOnMeasure(widthSpec, heightSpec);
+                return;
             }
 
             if (mAdapter != null) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
index be687c3..1547049 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -252,6 +252,66 @@
     }
 
     @Test
+    public void preditiveMeasuredCrashTest() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true) {
+            @Override
+            public void onAttachedToWindow(RecyclerView view) {
+                super.onAttachedToWindow(view);
+                assertThat(view.mLayout, is((RecyclerView.LayoutManager) this));
+            }
+
+            @Override
+            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+                super.onDetachedFromWindow(view, recycler);
+                assertThat(view.mLayout, is((RecyclerView.LayoutManager) this));
+            }
+
+            @Override
+            public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
+                    int widthSpec,
+                    int heightSpec) {
+                if (state.getItemCount() > 0) {
+                    // A typical LayoutManager will use a child view to measure the size.
+                    View v = recycler.getViewForPosition(0);
+                }
+                super.onMeasure(recycler, state, widthSpec, heightSpec);
+            }
+        };
+        lm.setSupportsPredictive(true);
+        lm.setAutoMeasureEnabled(false);
+        rv.setHasFixedSize(false);
+        final TestAdapter adapter = new TestAdapter(0);
+        rv.setAdapter(adapter);
+        rv.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(rv);
+        lm.waitForLayout(2);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                ViewGroup parent = (ViewGroup) rv.getParent();
+                parent.removeView(rv);
+                // setting RV as child of LinearLayout using MATCH_PARENT will cause
+                // RV.onMeasure() being called twice before layout(). This may cause crash.
+                LinearLayout linearLayout = new LinearLayout(parent.getContext());
+                linearLayout.setOrientation(LinearLayout.VERTICAL);
+                parent.addView(linearLayout,
+                        ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT);
+                linearLayout.addView(rv, ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT);
+
+            }
+        });
+
+        lm.expectLayouts(1);
+        adapter.addAndNotify(1);
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
     public void detachRvAndLayoutManagerProperly() throws Throwable {
         final RecyclerView rv = new RecyclerView(getActivity());
         final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true) {