blob: 1f0f3efff3fe0742c243ab8c2abc435517eb21d9 [file] [log] [blame]
/*
* 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 android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import android.graphics.Rect;
import android.test.suitebuilder.annotation.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 whether the layout manager can keep its children positions properly after it is re-laid
* out with larger/smaller intermediate size but the same final size.
*/
@MediumTest
@RunWith(Parameterized.class)
public class TestResizingRelayoutWithAutoMeasure extends BaseRecyclerViewInstrumentationTest {
private final RecyclerView.LayoutManager mLayoutManager;
private final float mWidthMultiplier;
private final float mHeightMultiplier;
public TestResizingRelayoutWithAutoMeasure(@SuppressWarnings("UnusedParameters") String name,
RecyclerView.LayoutManager layoutManager, float widthMultiplier,
float heightMultiplier) {
mLayoutManager = layoutManager;
mWidthMultiplier = widthMultiplier;
mHeightMultiplier = heightMultiplier;
}
@Parameterized.Parameters(name = "{0} w:{2} h:{3}")
public static List<Object[]> getParams() {
List<Object[]> params = new ArrayList<>();
for (float w : new float[]{.5f, 1f, 2f}) {
for (float h : new float[]{.5f, 1f, 2f}) {
params.add(
new Object[]{"linear layout", new LinearLayoutManager(null), w, h}
);
params.add(
new Object[]{"grid layout", new GridLayoutManager(null, 3), w, h}
);
params.add(
new Object[]{"staggered", new StaggeredGridLayoutManager(3,
StaggeredGridLayoutManager.VERTICAL), w, h}
);
}
}
return params;
}
@Test
public void testResizeDuringMeasurements() throws Throwable {
final RecyclerView recyclerView = new RecyclerView(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setAdapter(new TestAdapter(500));
setRecyclerView(recyclerView);
getInstrumentation().waitForIdleSync();
assertThat("Test sanity", recyclerView.getChildCount() > 0, is(true));
final int lastPosition = recyclerView.getAdapter().getItemCount() - 1;
smoothScrollToPosition(lastPosition);
assertThat("test sanity", recyclerView.findViewHolderForAdapterPosition(lastPosition),
notNullValue());
runTestOnUiThread(new Runnable() {
@Override
public void run() {
int startHeight = recyclerView.getMeasuredHeight();
int startWidth = recyclerView.getMeasuredWidth();
Map<Integer, Rect> startPositions = capturePositions(recyclerView);
recyclerView.measure(
makeMeasureSpec((int) (startWidth * mWidthMultiplier),
mWidthMultiplier == 1f ? EXACTLY : AT_MOST),
makeMeasureSpec((int) (startHeight * mHeightMultiplier),
mHeightMultiplier == 1f ? EXACTLY : AT_MOST));
recyclerView.measure(
makeMeasureSpec(startWidth, EXACTLY),
makeMeasureSpec(startHeight, EXACTLY));
recyclerView.dispatchLayout();
Map<Integer, Rect> endPositions = capturePositions(recyclerView);
assertStartItemPositions(startPositions, endPositions);
}
});
}
private void assertStartItemPositions(Map<Integer, Rect> startPositions,
Map<Integer, Rect> endPositions) {
for (Map.Entry<Integer, Rect> entry : startPositions.entrySet()) {
Rect rect = endPositions.get(entry.getKey());
assertThat("view for position " + entry.getKey() + " at" + entry.getValue(), rect,
notNullValue());
assertThat("rect for position " + entry.getKey(), entry.getValue(), is(rect));
}
}
private Map<Integer, Rect> capturePositions(RecyclerView recyclerView) {
Map<Integer, Rect> positions = new HashMap<>();
for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
View view = mLayoutManager.getChildAt(i);
int childAdapterPosition = recyclerView.getChildAdapterPosition(view);
Rect outRect = new Rect();
mLayoutManager.getDecoratedBoundsWithMargins(view, outRect);
// only record if outRect is visible
if (outRect.left >= mRecyclerView.getWidth() ||
outRect.top >= mRecyclerView.getHeight() ||
outRect.right < 0 ||
outRect.bottom < 0) {
continue;
}
positions.put(childAdapterPosition, outRect);
}
return positions;
}
}