/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.support.v7.widget; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import android.graphics.Rect; import android.support.test.filters.MediumTest; import android.view.View; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Tests dispatching no-op updates to the GLM and ensures it re-lays out items in the same location */ @MediumTest @RunWith(Parameterized.class) public class GridLayoutManagerNoOpUpdateTest extends BaseGridLayoutManagerTest { @Parameterized.Parameters(name = "conf:{0},rtl={1}") public static List getParams() { List result = new ArrayList<>(); for (BaseGridLayoutManagerTest.Config config : createBaseVariations()) { result.add(new Object[]{ config, true }); result.add(new Object[]{ config, false }); } return result; } private final Config mConfig; private final boolean mRtl; public GridLayoutManagerNoOpUpdateTest(Config config, boolean rtl) { mConfig = config; mRtl = rtl; } @Test public void rtlChanges() throws Throwable { RecyclerView rv = createRecyclerView(); mGlm.setFakeRtl(mRtl); waitForFirstLayout(rv); Map before = takeSnapshot(); View chosen = mGlm.findViewByPosition(1); assertNotNull("test sanity", chosen); mGlm.expectLayout(2); mAdapter.changeAndNotify(1, 1); mGlm.waitForLayout(2); Map after = takeSnapshot(); assertSnapshotsEqual(before, after); } private void assertSnapshotsEqual(Map before, Map after) { for (Map.Entry entry : before.entrySet()) { Rect newPosition = after.get(entry.getKey()); assertNotNull("cannot find " + entry.getKey() + " in after map", newPosition); assertEquals("position should be the same", entry.getValue(), newPosition); } assertEquals("visible view count should be equal", before.size(), after.size()); } private Map takeSnapshot() { Rect rvBounds = new Rect(); if (mRecyclerView.getClipToPadding()) { rvBounds.set(mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(), mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(), mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom()); } else { rvBounds.set(0, 0, mRecyclerView.getWidth(), mRecyclerView.getHeight()); } Map positionMap = new HashMap<>(); for (int i = 0; i < mGlm.getChildCount(); i++) { View child = mGlm.getChildAt(i); Rect childBounds = getChildBounds(mRecyclerView, child, true); long id = mRecyclerView.getChildViewHolder(child).getItemId(); if (rvBounds.intersect(childBounds)) { positionMap.put(id, childBounds); } } return positionMap; } private Rect getChildBounds(RecyclerView recyclerView, View child, boolean offset) { RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams(); Rect rect = new Rect(layoutManager.getDecoratedLeft(child) - lp.leftMargin, layoutManager.getDecoratedTop(child) - lp.topMargin, layoutManager.getDecoratedRight(child) + lp.rightMargin, layoutManager.getDecoratedBottom(child) + lp.bottomMargin); return rect; } private RecyclerView createRecyclerView() throws Throwable { GridTestAdapter adapter = new GridTestAdapter(mConfig.mItemCount); adapter.setHasStableIds(true); return setupBasic(mConfig, adapter); } }