14143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar/*
24143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
34143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar *
44143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
54143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * you may not use this file except in compliance with the License.
64143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * You may obtain a copy of the License at
74143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar *
84143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
94143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar *
104143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * Unless required by applicable law or agreed to in writing, software
114143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
124143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * See the License for the specific language governing permissions and
144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * limitations under the License.
154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar */
164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarpackage android.support.v7.widget;
174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
186b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyarimport static org.hamcrest.CoreMatchers.is;
196b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyarimport static org.hamcrest.MatcherAssert.assertThat;
206b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyarimport static org.junit.Assert.assertEquals;
216b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyarimport static org.junit.Assert.assertNull;
226b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyarimport static org.junit.Assert.assertTrue;
236b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar
2429f43aa1bb825a46fd7cf161a0cd1d5353aaf821Yigit Boyarimport android.app.Activity;
254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.graphics.Color;
264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.graphics.Rect;
274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.annotation.Nullable;
284143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.v4.util.LongSparseArray;
294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.v7.widget.TestedFrameLayout.FullControlLayoutParams;
304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.util.Log;
314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.view.Gravity;
324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.view.View;
334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.view.ViewGroup;
344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.widget.TextView;
354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
36f3844451301cb14ca885e125cb27f108a834c386Yigit Boyarimport org.hamcrest.CoreMatchers;
37959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar
384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport java.util.ArrayList;
394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport java.util.Collections;
404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport java.util.List;
414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar/**
434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * Class to test any generic wrap content behavior.
444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * It does so by running the same view scenario twice. Once with match parent setup to record all
454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * dimensions and once with wrap_content setup. Then compares all child locations & ids +
464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * RecyclerView size.
474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar */
484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarabstract public class BaseWrapContentTest extends BaseRecyclerViewInstrumentationTest {
494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    static final boolean DEBUG = false;
514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    static final String TAG = "WrapContentTest";
524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    RecyclerView.LayoutManager mLayoutManager;
534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    TestAdapter mTestAdapter;
554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    LoggingItemAnimator mLoggingItemAnimator;
574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    boolean mIsWrapContent;
594143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    protected final WrapContentConfig mWrapContentConfig;
614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    public BaseWrapContentTest(WrapContentConfig config) {
634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mWrapContentConfig = config;
644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    abstract RecyclerView.LayoutManager createLayoutManager();
674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
68f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar    void unspecifiedWithHintTest(boolean horizontal) throws Throwable {
69f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        final int itemHeight = 20;
70f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        final int itemWidth = 15;
71f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        RecyclerView.LayoutManager layoutManager = createLayoutManager();
72f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        WrappedRecyclerView rv = createRecyclerView(getActivity());
73f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        TestAdapter testAdapter = new TestAdapter(20) {
74f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            @Override
75f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            public void onBindViewHolder(TestViewHolder holder,
76f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar                    int position) {
77f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar                super.onBindViewHolder(holder, position);
78f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar                holder.itemView.setLayoutParams(new ViewGroup.LayoutParams(itemWidth, itemHeight));
79f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            }
80f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        };
81f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        rv.setLayoutManager(layoutManager);
82f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        rv.setAdapter(testAdapter);
83f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        TestedFrameLayout.FullControlLayoutParams lp =
84f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar                new TestedFrameLayout.FullControlLayoutParams(0, 0);
85f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        if (horizontal) {
86f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            lp.wSpec = View.MeasureSpec.makeMeasureSpec(25, View.MeasureSpec.UNSPECIFIED);
87f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            lp.hSpec = View.MeasureSpec.makeMeasureSpec(50, View.MeasureSpec.AT_MOST);
88f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        } else {
89f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            lp.hSpec = View.MeasureSpec.makeMeasureSpec(25, View.MeasureSpec.UNSPECIFIED);
90f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            lp.wSpec = View.MeasureSpec.makeMeasureSpec(50, View.MeasureSpec.AT_MOST);
91f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        }
92f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        rv.setLayoutParams(lp);
93f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        setRecyclerView(rv);
94f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        rv.waitUntilLayout();
95f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar
96f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        // we don't assert against the given size hint because LM will still ask for more if it
97f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        // lays out more children. This is the correct behavior because the spec is not AT_MOST,
98f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        // it is UNSPECIFIED.
99f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        if (horizontal) {
100f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            int expectedWidth = rv.getPaddingLeft() + rv.getPaddingRight() + itemWidth;
101f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            while (expectedWidth < 25) {
102f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar                expectedWidth += itemWidth;
103f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            }
104f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            assertThat(rv.getWidth(), CoreMatchers.is(expectedWidth));
105f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        } else {
106f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            int expectedHeight = rv.getPaddingTop() + rv.getPaddingBottom() + itemHeight;
107f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            while (expectedHeight < 25) {
108f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar                expectedHeight += itemHeight;
109f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            }
110f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar            assertThat(rv.getHeight(), CoreMatchers.is(expectedHeight));
111f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        }
112f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar    }
113f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar
1144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    protected void testScenerio(Scenario scenario) throws Throwable {
1154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        FullControlLayoutParams matchParent = new FullControlLayoutParams(
1164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                ViewGroup.LayoutParams.MATCH_PARENT,
1174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                ViewGroup.LayoutParams.MATCH_PARENT);
1184143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        FullControlLayoutParams wrapContent = new FullControlLayoutParams(
1194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                ViewGroup.LayoutParams.WRAP_CONTENT,
1204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                ViewGroup.LayoutParams.WRAP_CONTENT);
1214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (mWrapContentConfig.isUnlimitedHeight()) {
1224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            wrapContent.hSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
1234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
1244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (mWrapContentConfig.isUnlimitedWidth()) {
1254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            wrapContent.wSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
1264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
1274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
1284143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mIsWrapContent = false;
1294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        List<Snapshot> s1 = runScenario(scenario, matchParent, null);
1304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mIsWrapContent = true;
1314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
1324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        List<Snapshot> s2 = runScenario(scenario, wrapContent, s1);
1334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        assertEquals("test sanity", s1.size(), s2.size());
1344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
1354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        for (int i = 0; i < s1.size(); i++) {
1364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            Snapshot step1 = s1.get(i);
1374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            Snapshot step2 = s2.get(i);
1384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            step1.assertSame(step2, i);
1394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
1404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
1414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
1424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    public List<Snapshot> runScenario(Scenario scenario, ViewGroup.LayoutParams lp,
1434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            @Nullable List<Snapshot> compareWith)
1444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            throws Throwable {
1454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        removeRecyclerView();
1464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        Item.idCounter.set(0);
1474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        List<Snapshot> result = new ArrayList<>();
1484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        RecyclerView.LayoutManager layoutManager = scenario.createLayoutManager();
1494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        WrappedRecyclerView recyclerView = new WrappedRecyclerView(getActivity());
1504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.setBackgroundColor(Color.rgb(0, 0, 255));
1514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.setLayoutManager(layoutManager);
1524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.setLayoutParams(lp);
1534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mLayoutManager = layoutManager;
1544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mTestAdapter = new TestAdapter(scenario.getSeedAdapterSize());
1554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.setAdapter(mTestAdapter);
1564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mLoggingItemAnimator = new LoggingItemAnimator();
1574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.setItemAnimator(mLoggingItemAnimator);
1584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        setRecyclerView(recyclerView);
1594143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.waitUntilLayout();
1604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        int stepIndex = 0;
1614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        for (Step step : scenario.mStepList) {
1624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            mLoggingItemAnimator.reset();
1634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            step.onRun();
1644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            recyclerView.waitUntilLayout();
1654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            recyclerView.waitUntilAnimations();
1664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            Snapshot snapshot = takeSnapshot();
1674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (mIsWrapContent) {
1684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                snapshot.assertRvSize();
1694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
1704143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            result.add(snapshot);
1714143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (compareWith != null) {
1724143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                compareWith.get(stepIndex).assertSame(snapshot, stepIndex);
1734143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
1744143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            stepIndex++;
1754143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
1764143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.waitUntilLayout();
1774143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.waitUntilAnimations();
1784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        Snapshot snapshot = takeSnapshot();
1794143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (mIsWrapContent) {
1804143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            snapshot.assertRvSize();
1814143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
1824143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        result.add(snapshot);
1834143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (compareWith != null) {
1844143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            compareWith.get(stepIndex).assertSame(snapshot, stepIndex);
1854143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
1864143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        return result;
1874143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
1884143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
18929f43aa1bb825a46fd7cf161a0cd1d5353aaf821Yigit Boyar    protected WrappedRecyclerView createRecyclerView(Activity activity) {
19029f43aa1bb825a46fd7cf161a0cd1d5353aaf821Yigit Boyar        return new WrappedRecyclerView(getActivity());
19129f43aa1bb825a46fd7cf161a0cd1d5353aaf821Yigit Boyar    }
19229f43aa1bb825a46fd7cf161a0cd1d5353aaf821Yigit Boyar
1934143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    void layoutAndCheck(TestedFrameLayout.FullControlLayoutParams lp,
1944143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            BaseWrapContentWithAspectRatioTest.WrapContentAdapter adapter, Rect[] expected,
1954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            int width, int height) throws Throwable {
19629f43aa1bb825a46fd7cf161a0cd1d5353aaf821Yigit Boyar        WrappedRecyclerView recyclerView = createRecyclerView(getActivity());
1974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.setBackgroundColor(Color.rgb(0, 0, 255));
1984143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.setLayoutManager(createLayoutManager());
1994143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.setAdapter(adapter);
2004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.setLayoutParams(lp);
2016b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        Rect padding = mWrapContentConfig.padding;
202de8a5de43b647f9b61f4859a22a0ce59155f442aYigit Boyar        recyclerView.setPadding(padding.left, padding.top, padding.right, padding.bottom);
2034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        setRecyclerView(recyclerView);
2044143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        recyclerView.waitUntilLayout();
2054143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        Snapshot snapshot = takeSnapshot();
2064143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        int index = 0;
2076b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        Rect tmp = new Rect();
2084143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        for (BaseWrapContentWithAspectRatioTest.MeasureBehavior behavior : adapter.behaviors) {
2096b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar            tmp.set(expected[index]);
2106b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar            tmp.offset(padding.left, padding.top);
2114143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            assertThat("behavior " + index, snapshot.mChildCoordinates.get(behavior.getId()),
2126b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar                    is(tmp));
2134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            index ++;
2144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
2154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        Rect boundingBox = new Rect(0, 0, 0, 0);
2164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        for (Rect rect : expected) {
2174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            boundingBox.union(rect);
2184143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
2196b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        assertThat(recyclerView.getWidth(), is(width + padding.left + padding.right));
2206b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        assertThat(recyclerView.getHeight(), is(height + padding.top + padding.bottom));
2214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
2224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    abstract protected int getVerticalGravity(RecyclerView.LayoutManager layoutManager);
2254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    abstract protected int getHorizontalGravity(RecyclerView.LayoutManager layoutManager);
2274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2284143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    protected Snapshot takeSnapshot() throws Throwable {
2294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        Snapshot snapshot = new Snapshot(mRecyclerView, mLoggingItemAnimator,
2304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                getHorizontalGravity(mLayoutManager), getVerticalGravity(mLayoutManager));
2314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        return snapshot;
2324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
2334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    abstract class Scenario {
2354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        ArrayList<Step> mStepList = new ArrayList<>();
2374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public Scenario(Step... steps) {
2394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            Collections.addAll(mStepList, steps);
2404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
2414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public int getSeedAdapterSize() {
2434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return 10;
2444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
2454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public RecyclerView.LayoutManager createLayoutManager() {
2474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return BaseWrapContentTest.this.createLayoutManager();
2484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
2494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
2504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    abstract static class Step {
2524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        abstract void onRun() throws Throwable;
2544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
2554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    class Snapshot {
2574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        Rect mRawChildrenBox = new Rect();
2594143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        Rect mRvSize = new Rect();
2614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        Rect mRvPadding = new Rect();
2634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        Rect mRvParentSize = new Rect();
2654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        LongSparseArray<Rect> mChildCoordinates = new LongSparseArray<>();
2674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        LongSparseArray<String> mAppear = new LongSparseArray<>();
2694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2704143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        LongSparseArray<String> mDisappear = new LongSparseArray<>();
2714143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2724143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        LongSparseArray<String> mPersistent = new LongSparseArray<>();
2734143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2744143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        LongSparseArray<String> mChanged = new LongSparseArray<>();
2754143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2764143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        int mVerticalGravity;
2774143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        int mHorizontalGravity;
2794143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2804143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        int mOffsetX, mOffsetY;// how much we should offset children
2814143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2824143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public Snapshot(RecyclerView recyclerView, LoggingItemAnimator loggingItemAnimator,
2834143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                int horizontalGravity, int verticalGravity)
2844143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                throws Throwable {
2854143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            mRvSize = getViewBounds(recyclerView);
2864143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            mRvParentSize = getViewBounds((View) recyclerView.getParent());
2874143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            mRvPadding = new Rect(recyclerView.getPaddingLeft(), recyclerView.getPaddingTop(),
2884143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    recyclerView.getPaddingRight(), recyclerView.getPaddingBottom());
2894143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            mVerticalGravity = verticalGravity;
2904143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            mHorizontalGravity = horizontalGravity;
2914143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (mVerticalGravity == Gravity.TOP) {
2924143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                mOffsetY = 0;
2934143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            } else {
2944143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                mOffsetY = mRvParentSize.bottom - mRvSize.bottom;
2954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
2964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
2974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (mHorizontalGravity == Gravity.LEFT) {
2984143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                mOffsetX = 0;
2994143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            } else {
3004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                mOffsetX = mRvParentSize.right - mRvSize.right;
3014143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
3024143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            collectChildCoordinates(recyclerView);
3034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (loggingItemAnimator != null) {
3044143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                collectInto(mAppear, loggingItemAnimator.mAnimateAppearanceList);
3054143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                collectInto(mDisappear, loggingItemAnimator.mAnimateDisappearanceList);
3064143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                collectInto(mPersistent, loggingItemAnimator.mAnimatePersistenceList);
3074143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                collectInto(mChanged, loggingItemAnimator.mAnimateChangeList);
3084143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
3094143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
3104143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
3114143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public boolean doesChildrenFitVertically() {
3124143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return mRawChildrenBox.top >= mRvPadding.top
3134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    && mRawChildrenBox.bottom <= mRvSize.bottom - mRvPadding.bottom;
3144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
3154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
3164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public boolean doesChildrenFitHorizontally() {
3174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return mRawChildrenBox.left >= mRvPadding.left
3184143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    && mRawChildrenBox.right <= mRvSize.right - mRvPadding.right;
3194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
3204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
3214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public void assertSame(Snapshot other, int step) {
3224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (mWrapContentConfig.isUnlimitedHeight() &&
3234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    (!doesChildrenFitVertically() || !other.doesChildrenFitVertically())) {
3244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                if (DEBUG) {
3254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    Log.d(TAG, "cannot assert coordinates because it does not fit vertically");
3264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                }
3274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                return;
3284143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
3294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (mWrapContentConfig.isUnlimitedWidth() &&
3304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    (!doesChildrenFitHorizontally() || !other.doesChildrenFitHorizontally())) {
3314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                if (DEBUG) {
3324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    Log.d(TAG, "cannot assert coordinates because it does not fit horizontally");
3334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                }
3344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                return;
3354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
3364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            assertMap("child coordinates. step:" + step, mChildCoordinates,
3374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    other.mChildCoordinates);
3384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (mWrapContentConfig.isUnlimitedHeight() || mWrapContentConfig.isUnlimitedWidth()) {
3394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                return;//cannot assert animatinos in unlimited size
3404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
3414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            assertMap("appearing step:" + step, mAppear, other.mAppear);
3424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            assertMap("disappearing step:" + step, mDisappear, other.mDisappear);
3434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            assertMap("persistent step:" + step, mPersistent, other.mPersistent);
3444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            assertMap("changed step:" + step, mChanged, other.mChanged);
3454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
3464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
3474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        private void assertMap(String prefix, LongSparseArray<?> map1, LongSparseArray<?> map2) {
3484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            StringBuilder logBuilder = new StringBuilder();
3494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            logBuilder.append(prefix).append("\n");
3504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            logBuilder.append("map1").append("\n");
3514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            logInto(map1, logBuilder);
3524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            logBuilder.append("map2").append("\n");
3534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            logInto(map2, logBuilder);
3544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            final String log = logBuilder.toString();
3554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            assertEquals(log + " same size", map1.size(), map2.size());
3564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            for (int i = 0; i < map1.size(); i++) {
3574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                assertAtIndex(log, map1, map2, i);
3584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
3594143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
3604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
3614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        private void assertAtIndex(String prefix, LongSparseArray<?> map1, LongSparseArray<?> map2,
3624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                int index) {
3634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            long key1 = map1.keyAt(index);
3644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            long key2 = map2.keyAt(index);
3654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            assertEquals(prefix + "key mismatch at index " + index, key1, key2);
3664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            Object value1 = map1.valueAt(index);
3674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            Object value2 = map2.valueAt(index);
3684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            assertEquals(prefix + " value mismatch at index " + index, value1, value2);
3694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
3704143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
3714143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        private void logInto(LongSparseArray<?> map, StringBuilder sb) {
3724143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            for (int i = 0; i < map.size(); i++) {
3734143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                long key = map.keyAt(i);
3744143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                Object value = map.valueAt(i);
3754143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                sb.append(key).append(" : ").append(value).append("\n");
3764143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
3774143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
3784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
3794143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        @Override
3804143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public String toString() {
3814143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            StringBuilder sb = new StringBuilder("Snapshot{\n");
3824143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            sb.append("child coordinates:\n");
3834143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            logInto(mChildCoordinates, sb);
3844143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            sb.append("appear animations:\n");
3854143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            logInto(mAppear, sb);
3864143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            sb.append("disappear animations:\n");
3874143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            logInto(mDisappear, sb);
3884143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            sb.append("change animations:\n");
3894143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            logInto(mChanged, sb);
3904143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            sb.append("persistent animations:\n");
3914143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            logInto(mPersistent, sb);
3924143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            sb.append("}");
3934143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return sb.toString();
3944143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
3954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
3964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        @Override
3974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public int hashCode() {
3984143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            int result = mChildCoordinates.hashCode();
3994143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            result = 31 * result + mAppear.hashCode();
4004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            result = 31 * result + mDisappear.hashCode();
4014143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            result = 31 * result + mPersistent.hashCode();
4024143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            result = 31 * result + mChanged.hashCode();
4034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return result;
4044143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
4054143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4064143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        private void collectInto(
4074143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                LongSparseArray<String> target,
4084143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                List<? extends BaseRecyclerViewAnimationsTest.AnimateLogBase> list) {
4094143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            for (BaseRecyclerViewAnimationsTest.AnimateLogBase base : list) {
4104143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                long id = getItemId(base.viewHolder);
4114143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                assertNull(target.get(id));
4124143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                target.put(id, log(base));
4134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
4144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
4154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        private String log(BaseRecyclerViewAnimationsTest.AnimateLogBase base) {
4174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return base.getClass().getSimpleName() +
4184143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    ((TextView) base.viewHolder.itemView).getText() + ": " +
4194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    "[pre:" + log(base.postInfo) +
4204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    ", post:" + log(base.postInfo) + "]";
4214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
4224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        private String log(BaseRecyclerViewAnimationsTest.LoggingInfo postInfo) {
4244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (postInfo == null) {
4254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                return "?";
4264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
4274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return "PI[flags: " + postInfo.changeFlags
4284143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    + ",l:" + (postInfo.left + mOffsetX)
4294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    + ",t:" + (postInfo.top + mOffsetY)
4304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    + ",r:" + (postInfo.right + mOffsetX)
4314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    + ",b:" + (postInfo.bottom + mOffsetY) + "]";
4324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
4334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        void collectChildCoordinates(RecyclerView recyclerView) throws Throwable {
4354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            mRawChildrenBox = new Rect(0, 0, 0, 0);
4364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            final int childCount = recyclerView.getChildCount();
4374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            for (int i = 0; i < childCount; i++) {
4384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                View child = recyclerView.getChildAt(i);
4394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                Rect childBounds = getChildBounds(recyclerView, child, true);
4404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                mRawChildrenBox.union(getChildBounds(recyclerView, child, false));
4414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                RecyclerView.ViewHolder childViewHolder = recyclerView.getChildViewHolder(child);
4424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                mChildCoordinates.put(getItemId(childViewHolder), childBounds);
4434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
4444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
4454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        private Rect getViewBounds(View view) {
4474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
4484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
4494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        private Rect getChildBounds(RecyclerView recyclerView, View child, boolean offset) {
4514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
4524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
4534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            Rect rect = new Rect(layoutManager.getDecoratedLeft(child) - lp.leftMargin,
4544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    layoutManager.getDecoratedTop(child) - lp.topMargin,
4554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    layoutManager.getDecoratedRight(child) + lp.rightMargin,
4564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    layoutManager.getDecoratedBottom(child) + lp.bottomMargin);
4574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (offset) {
4584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                rect.offset(mOffsetX, mOffsetY);
4594143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
4604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return rect;
4614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
4624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        private long getItemId(RecyclerView.ViewHolder vh) {
4644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (vh instanceof TestViewHolder) {
4654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                return ((TestViewHolder) vh).mBoundItem.mId;
4664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            } else if (vh instanceof BaseWrapContentWithAspectRatioTest.WrapContentViewHolder) {
4674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                BaseWrapContentWithAspectRatioTest.WrapContentViewHolder casted =
4684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        (BaseWrapContentWithAspectRatioTest.WrapContentViewHolder) vh;
4694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                return casted.mView.mBehavior.getId();
4704143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            } else {
4714143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                throw new IllegalArgumentException("i don't support any VH");
4724143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
4734143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
4744143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4754143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public void assertRvSize() {
4764143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (shouldWrapContentHorizontally()) {
4774143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                int expectedW = mRawChildrenBox.width() + mRvPadding.left + mRvPadding.right;
4784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                assertTrue(mRvSize.width() + " <= " + expectedW, mRvSize.width() <= expectedW);
4794143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
4804143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (shouldWrapContentVertically()) {
4814143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                int expectedH = mRawChildrenBox.height() + mRvPadding.top + mRvPadding.bottom;
4824143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                assertTrue(mRvSize.height() + "<=" + expectedH, mRvSize.height() <= expectedH);
4834143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
4844143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
4854143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
4864143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4874143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    protected boolean shouldWrapContentHorizontally() {
4884143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        return true;
4894143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
4904143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4914143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    protected boolean shouldWrapContentVertically() {
4924143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        return true;
4934143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
4944143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    static class WrapContentConfig {
4964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
4976b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        public boolean unlimitedWidth;
4986b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        public boolean unlimitedHeight;
4996b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        public Rect padding = new Rect(0, 0, 0, 0);
5004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
5014143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public WrapContentConfig(boolean unlimitedWidth, boolean unlimitedHeight) {
5024143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            this.unlimitedWidth = unlimitedWidth;
5034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            this.unlimitedHeight = unlimitedHeight;
5044143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
5054143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
5066b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        public WrapContentConfig(boolean unlimitedWidth, boolean unlimitedHeight, Rect padding) {
5076b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar            this.unlimitedWidth = unlimitedWidth;
5086b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar            this.unlimitedHeight = unlimitedHeight;
5096b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar            this.padding.set(padding);
5106b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        }
5116b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar
5124143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public boolean isUnlimitedWidth() {
5134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return unlimitedWidth;
5144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
5154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
5164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public WrapContentConfig setUnlimitedWidth(boolean unlimitedWidth) {
5174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            this.unlimitedWidth = unlimitedWidth;
5184143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return this;
5194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
5204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
5214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public boolean isUnlimitedHeight() {
5224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return unlimitedHeight;
5234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
5244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
5254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public WrapContentConfig setUnlimitedHeight(boolean unlimitedHeight) {
5264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            this.unlimitedHeight = unlimitedHeight;
5274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return this;
5284143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
5294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
5304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        @Override
5314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public String toString() {
5326b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar            return "WrapContentConfig{"
5336b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar                    + "unlimitedWidth=" + unlimitedWidth
534e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas                    + ",unlimitedHeight=" + unlimitedHeight
535e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas                    + ",padding=" + padding
5366b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar                    + '}';
5374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
5384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
5394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public TestedFrameLayout.FullControlLayoutParams toLayoutParams(int wDim, int hDim) {
5404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            TestedFrameLayout.FullControlLayoutParams
5414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    lp = new TestedFrameLayout.FullControlLayoutParams(
5424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    wDim, hDim);
5434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (unlimitedWidth) {
5444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                lp.wSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
5454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
5464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (unlimitedHeight) {
5474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                lp.hSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
5484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
5494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return lp;
5504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
5514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
5524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar}
553