1 /* 2 * Copyright (C) 2016 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 android.support.v7.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.view.View; 24 25 import org.junit.Test; 26 import org.junit.runner.RunWith; 27 import org.junit.runners.Parameterized; 28 29 import java.util.ArrayList; 30 import java.util.HashMap; 31 import java.util.List; 32 import java.util.Map; 33 34 /** 35 * Tests dispatching no-op updates to the GLM and ensures it re-lays out items in the same location 36 */ 37 @RunWith(Parameterized.class) 38 public class GridLayoutManagerNoOpUpdateTest extends BaseGridLayoutManagerTest { 39 @Parameterized.Parameters(name = "conf:{0} rtl={1}") getParams()40 public static List<Object[]> getParams() { 41 List<Object[]> result = new ArrayList<>(); 42 for (BaseGridLayoutManagerTest.Config config : createBaseVariations()) { 43 result.add(new Object[]{ 44 config, 45 true 46 }); 47 result.add(new Object[]{ 48 config, 49 false 50 }); 51 } 52 return result; 53 } 54 55 private final Config mConfig; 56 private final boolean mRtl; 57 GridLayoutManagerNoOpUpdateTest(Config config, boolean rtl)58 public GridLayoutManagerNoOpUpdateTest(Config config, boolean rtl) { 59 mConfig = config; 60 mRtl = rtl; 61 } 62 63 @Test rtlChanges()64 public void rtlChanges() throws Throwable { 65 RecyclerView rv = createRecyclerView(); 66 mGlm.setFakeRtl(mRtl); 67 waitForFirstLayout(rv); 68 Map<Long, Rect> before = takeSnapshot(); 69 70 View chosen = mGlm.findViewByPosition(1); 71 assertNotNull("test sanity", chosen); 72 mGlm.expectLayout(2); 73 mAdapter.changeAndNotify(1, 1); 74 mGlm.waitForLayout(2); 75 Map<Long, Rect> after = takeSnapshot(); 76 assertSnapshotsEqual(before, after); 77 } 78 assertSnapshotsEqual(Map<Long, Rect> before, Map<Long, Rect> after)79 private void assertSnapshotsEqual(Map<Long, Rect> before, Map<Long, Rect> after) { 80 for (Map.Entry<Long, Rect> entry : before.entrySet()) { 81 Rect newPosition = after.get(entry.getKey()); 82 assertNotNull("cannot find " + entry.getKey() + " in after map", newPosition); 83 assertEquals("position should be the same", entry.getValue(), newPosition); 84 } 85 assertEquals("visible view count should be equal", before.size(), after.size()); 86 } 87 takeSnapshot()88 private Map<Long, Rect> takeSnapshot() { 89 Rect rvBounds = new Rect(); 90 if (mRecyclerView.getClipToPadding()) { 91 rvBounds.set(mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(), 92 mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(), 93 mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom()); 94 } else { 95 rvBounds.set(0, 0, mRecyclerView.getWidth(), mRecyclerView.getHeight()); 96 } 97 Map<Long, Rect> positionMap = new HashMap<>(); 98 for (int i = 0; i < mGlm.getChildCount(); i++) { 99 View child = mGlm.getChildAt(i); 100 Rect childBounds = getChildBounds(mRecyclerView, child, true); 101 long id = mRecyclerView.getChildViewHolder(child).getItemId(); 102 if (rvBounds.intersect(childBounds)) { 103 positionMap.put(id, childBounds); 104 } 105 } 106 return positionMap; 107 } 108 getChildBounds(RecyclerView recyclerView, View child, boolean offset)109 private Rect getChildBounds(RecyclerView recyclerView, View child, boolean offset) { 110 RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); 111 RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams(); 112 Rect rect = new Rect(layoutManager.getDecoratedLeft(child) - lp.leftMargin, 113 layoutManager.getDecoratedTop(child) - lp.topMargin, 114 layoutManager.getDecoratedRight(child) + lp.rightMargin, 115 layoutManager.getDecoratedBottom(child) + lp.bottomMargin); 116 return rect; 117 } 118 createRecyclerView()119 private RecyclerView createRecyclerView() throws Throwable { 120 GridTestAdapter adapter = new GridTestAdapter(mConfig.mItemCount); 121 adapter.setHasStableIds(true); 122 return setupBasic(mConfig, adapter); 123 } 124 } 125