Fixed fastRelayout when a view is invalidated

The views that are off the screen are cached and invalidated after a
layout. getAdapterPositionByView returns NO_POSITION for such views that
was causing crash in fastRelayout when getViewForPosition was called.
Now will skip laying out children when such a view is encountered.

Bug: 62448243
Test: testLayoutWhenAViewIsInvalidated
Change-Id: I5bb86682dba0bff6a4a5e77438b4735a2a720345
(cherry picked from commit e79b22a10835076150c04e96c52d8342b3af8409)
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
index 35238cf..ff2d999 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -1882,7 +1882,9 @@
             View view = getChildAt(index);
             position = getAdapterPositionByView(view);
             Grid.Location location = mGrid.getLocation(position);
-            if (location == null) {
+            // position could be NO_POSITION for the views off the screen that were cached. For
+            // these views markKnownViewsInvalid invalidates them.
+            if (location == null || (position == NO_POSITION)) {
                 if (DEBUG) Log.w(getTag(), "fastRelayout(): no Location at " + position);
                 invalidateAfter = true;
                 break;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
index 5bc5af4..a6f005d 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -778,6 +778,39 @@
         verifyEdgesSame(endEdges, endEdges2);
     }
 
+
+    @Test
+    public void testLayoutWhenAViewIsInvalidated() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+        mNumRows = 1;
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        waitOneUiCycle();
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                RecyclerView.ViewHolder vh = mGridView.findViewHolderForAdapterPosition(3);
+                // The following is nowhere ideal since we can't override GridLayoutManager to
+                // obtain a reference to Recycler. Ideally, this test should call
+                // addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID) on the ViewHolder to
+                // simulate markKnownViewsInvalid on the cached views in RecyclerView.
+                mLayoutManager.stopIgnoringView(vh.itemView);
+            }
+        });
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+    }
+
+
     void preparePredictiveLayout() throws Throwable {
         Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,