1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.recyclerview.widget; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 22 import android.graphics.Rect; 23 import android.support.test.filters.MediumTest; 24 import android.view.View; 25 26 import org.junit.Test; 27 import org.junit.runner.RunWith; 28 import org.junit.runners.Parameterized; 29 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.List; 33 import java.util.Map; 34 35 /** 36 * Tests dispatching no-op updates to the GLM and ensures it re-lays out items in the same location 37 */ 38 @MediumTest 39 @RunWith(Parameterized.class) 40 public class GridLayoutManagerNoOpUpdateTest extends BaseGridLayoutManagerTest { 41 @Parameterized.Parameters(name = "conf:{0},rtl={1}") getParams()42 public static List<Object[]> getParams() { 43 List<Object[]> result = new ArrayList<>(); 44 for (BaseGridLayoutManagerTest.Config config : createBaseVariations()) { 45 result.add(new Object[]{ 46 config, 47 true 48 }); 49 result.add(new Object[]{ 50 config, 51 false 52 }); 53 } 54 return result; 55 } 56 57 private final Config mConfig; 58 private final boolean mRtl; 59 GridLayoutManagerNoOpUpdateTest(Config config, boolean rtl)60 public GridLayoutManagerNoOpUpdateTest(Config config, boolean rtl) { 61 mConfig = config; 62 mRtl = rtl; 63 } 64 65 @Test rtlChanges()66 public void rtlChanges() throws Throwable { 67 RecyclerView rv = createRecyclerView(); 68 mGlm.setFakeRtl(mRtl); 69 waitForFirstLayout(rv); 70 Map<Long, Rect> before = takeSnapshot(); 71 72 View chosen = mGlm.findViewByPosition(1); 73 assertNotNull("test sanity", chosen); 74 mGlm.expectLayout(2); 75 mAdapter.changeAndNotify(1, 1); 76 mGlm.waitForLayout(2); 77 Map<Long, Rect> after = takeSnapshot(); 78 assertSnapshotsEqual(before, after); 79 } 80 assertSnapshotsEqual(Map<Long, Rect> before, Map<Long, Rect> after)81 private void assertSnapshotsEqual(Map<Long, Rect> before, Map<Long, Rect> after) { 82 for (Map.Entry<Long, Rect> entry : before.entrySet()) { 83 Rect newPosition = after.get(entry.getKey()); 84 assertNotNull("cannot find " + entry.getKey() + " in after map", newPosition); 85 assertEquals("position should be the same", entry.getValue(), newPosition); 86 } 87 assertEquals("visible view count should be equal", before.size(), after.size()); 88 } 89 takeSnapshot()90 private Map<Long, Rect> takeSnapshot() { 91 Rect rvBounds = new Rect(); 92 if (mRecyclerView.getClipToPadding()) { 93 rvBounds.set(mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(), 94 mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(), 95 mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom()); 96 } else { 97 rvBounds.set(0, 0, mRecyclerView.getWidth(), mRecyclerView.getHeight()); 98 } 99 Map<Long, Rect> positionMap = new HashMap<>(); 100 for (int i = 0; i < mGlm.getChildCount(); i++) { 101 View child = mGlm.getChildAt(i); 102 Rect childBounds = getChildBounds(mRecyclerView, child, true); 103 long id = mRecyclerView.getChildViewHolder(child).getItemId(); 104 if (rvBounds.intersect(childBounds)) { 105 positionMap.put(id, childBounds); 106 } 107 } 108 return positionMap; 109 } 110 getChildBounds(RecyclerView recyclerView, View child, boolean offset)111 private Rect getChildBounds(RecyclerView recyclerView, View child, boolean offset) { 112 RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); 113 RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams(); 114 Rect rect = new Rect(layoutManager.getDecoratedLeft(child) - lp.leftMargin, 115 layoutManager.getDecoratedTop(child) - lp.topMargin, 116 layoutManager.getDecoratedRight(child) + lp.rightMargin, 117 layoutManager.getDecoratedBottom(child) + lp.bottomMargin); 118 return rect; 119 } 120 createRecyclerView()121 private RecyclerView createRecyclerView() throws Throwable { 122 GridTestAdapter adapter = new GridTestAdapter(mConfig.mItemCount); 123 adapter.setHasStableIds(true); 124 return setupBasic(mConfig, adapter); 125 } 126 } 127