blob: c077088b6017a5fdb2d5736718fe3a139da7efeb [file] [log] [blame]
/*
* Copyright 2018 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 androidx.recyclerview.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<Object[]> getParams() {
List<Object[]> 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<Long, Rect> before = takeSnapshot();
View chosen = mGlm.findViewByPosition(1);
assertNotNull("test sanity", chosen);
mGlm.expectLayout(2);
mAdapter.changeAndNotify(1, 1);
mGlm.waitForLayout(2);
Map<Long, Rect> after = takeSnapshot();
assertSnapshotsEqual(before, after);
}
private void assertSnapshotsEqual(Map<Long, Rect> before, Map<Long, Rect> after) {
for (Map.Entry<Long, Rect> 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<Long, Rect> 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<Long, Rect> 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);
}
}