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,