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
17package android.support.v7.widget;
18
19import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
20import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
21import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
22import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
23
24import static org.hamcrest.MatcherAssert.assertThat;
25
26import android.graphics.Color;
27import android.support.test.filters.MediumTest;
28import android.view.View;
29import android.view.ViewGroup;
30
31import org.hamcrest.CoreMatchers;
32import org.junit.Test;
33import org.junit.runner.RunWith;
34import org.junit.runners.Parameterized;
35
36import java.util.ArrayList;
37import java.util.List;
38
39@RunWith(Parameterized.class)
40@MediumTest
41public class LinearLayoutManagerWrapContentWithAspectRatioTest
42        extends BaseWrapContentWithAspectRatioTest {
43
44    final LinearLayoutManagerTest.Config mConfig;
45    final float mRatio;
46
47    public LinearLayoutManagerWrapContentWithAspectRatioTest(
48            BaseLinearLayoutManagerTest.Config config,
49            BaseWrapContentTest.WrapContentConfig wrapContentConfig,
50            float ratio) {
51        super(wrapContentConfig);
52        mConfig = config;
53        mRatio = ratio;
54    }
55
56    @Parameterized.Parameters(name = "{0},{1},ratio:{2}")
57    public static Iterable<Object[]> data() {
58        List<Object[]> params = new ArrayList<>();
59        for (float ratio : new float[]{.5f, 1f, 2f}) {
60            for (int orientation : new int[]{VERTICAL, HORIZONTAL}) {
61                for (boolean reverseLayout : new boolean[]{false, true}) {
62                    for (boolean stackFromBottom : new boolean[]{false, true}) {
63                        params.add(
64                                new Object[]{
65                                        new BaseLinearLayoutManagerTest.Config(orientation,
66                                                reverseLayout, stackFromBottom),
67                                        new BaseWrapContentTest.WrapContentConfig(
68                                                false, false),
69                                        ratio
70                                }
71                        );
72                        params.add(
73                                new Object[]{
74                                        new BaseLinearLayoutManagerTest.Config(orientation,
75                                                reverseLayout, stackFromBottom),
76                                        new BaseWrapContentTest.WrapContentConfig(
77                                                HORIZONTAL == orientation,
78                                                VERTICAL == orientation),
79                                        ratio
80                                }
81                        );
82                        params.add(
83                                new Object[]{
84                                        new BaseLinearLayoutManagerTest.Config(orientation,
85                                                reverseLayout, stackFromBottom),
86                                        new BaseWrapContentTest.WrapContentConfig(
87                                                VERTICAL == orientation,
88                                                HORIZONTAL == orientation),
89                                        ratio
90                                }
91                        );
92                        params.add(
93                                new Object[]{
94                                        new BaseLinearLayoutManagerTest.Config(orientation,
95                                                reverseLayout, stackFromBottom),
96                                        new BaseWrapContentTest.WrapContentConfig(
97                                                true, true),
98                                        ratio
99                                }
100                        );
101                    }
102                }
103            }
104        }
105        return params;
106    }
107
108    @Test
109    public void wrapContentAffectsOtherOrientation() throws Throwable {
110        TestedFrameLayout.FullControlLayoutParams
111                wrapContent = new TestedFrameLayout.FullControlLayoutParams(
112                ViewGroup.LayoutParams.WRAP_CONTENT,
113                ViewGroup.LayoutParams.WRAP_CONTENT);
114        int testOrientation = mConfig.mOrientation == VERTICAL ? HORIZONTAL : VERTICAL;
115        boolean unlimitedSize = false;
116        if (mWrapContentConfig.isUnlimitedHeight()) {
117            wrapContent.hSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
118            unlimitedSize = testOrientation == VERTICAL;
119        }
120        if (mWrapContentConfig.isUnlimitedWidth()) {
121            wrapContent.wSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
122            unlimitedSize |= testOrientation == HORIZONTAL;
123        }
124
125        RecyclerView.LayoutManager layoutManager = createFromConfig();
126        WrappedRecyclerView
127                recyclerView = new WrappedRecyclerView(getActivity());
128        recyclerView.setBackgroundColor(Color.rgb(0, 0, 255));
129        recyclerView.setLayoutManager(layoutManager);
130        recyclerView.setLayoutParams(wrapContent);
131
132        AspectRatioMeasureBehavior behavior1 = new AspectRatioMeasureBehavior(10, 10,
133                WRAP_CONTENT, WRAP_CONTENT).aspectRatio(testOrientation, mRatio);
134        AspectRatioMeasureBehavior behavior2 = new AspectRatioMeasureBehavior(15, 15,
135                testOrientation == HORIZONTAL ? MATCH_PARENT : WRAP_CONTENT,
136                testOrientation == VERTICAL ? MATCH_PARENT : WRAP_CONTENT)
137                .aspectRatio(testOrientation, mRatio);
138        AspectRatioMeasureBehavior behavior3 = new AspectRatioMeasureBehavior(8, 8,
139                testOrientation == HORIZONTAL ? MATCH_PARENT : WRAP_CONTENT,
140                testOrientation == VERTICAL ? MATCH_PARENT : WRAP_CONTENT)
141                .aspectRatio(testOrientation, mRatio);
142
143        WrapContentAdapter adapter = new WrapContentAdapter(
144                behavior1, behavior2, behavior3
145        );
146
147        recyclerView.setAdapter(adapter);
148        setRecyclerView(recyclerView);
149        recyclerView.waitUntilLayout();
150
151        int parentDim = getSize((View) recyclerView.getParent(), testOrientation);
152
153        View itemView1 = recyclerView.findViewHolderForAdapterPosition(0).itemView;
154        assertThat("first child test size", getSize(itemView1, testOrientation),
155                CoreMatchers.is(10));
156        assertThat("first child dependant size", getSize(itemView1, mConfig.mOrientation),
157                CoreMatchers.is(behavior1.getSecondary(10)));
158
159        View itemView2 = recyclerView.findViewHolderForAdapterPosition(1).itemView;
160        assertThat("second child test size", getSize(itemView2, testOrientation),
161                CoreMatchers.is(15));
162        assertThat("second child dependant size", getSize(itemView2, mConfig.mOrientation),
163                CoreMatchers.is(behavior2.getSecondary(15)));
164
165        View itemView3 = recyclerView.findViewHolderForAdapterPosition(2).itemView;
166        assertThat("third child test size", getSize(itemView3, testOrientation),
167                CoreMatchers.is(15));
168        assertThat("third child dependant size", getSize(itemView3, mConfig.mOrientation),
169                CoreMatchers.is(behavior3.getSecondary(15)));
170
171        assertThat("it should be measured only once", behavior1.measureSpecs.size(),
172                CoreMatchers.is(1));
173        if (unlimitedSize) {
174            assertThat(behavior1.getSpec(0, testOrientation),
175                    MeasureSpecMatcher.is(0, View.MeasureSpec.UNSPECIFIED));
176        } else {
177            assertThat(behavior1.getSpec(0, testOrientation),
178                    MeasureSpecMatcher.is(parentDim, View.MeasureSpec.AT_MOST));
179        }
180
181        assertThat("it should be measured once", behavior2.measureSpecs.size(), CoreMatchers.is(1));
182        if (unlimitedSize) {
183            assertThat(behavior2.getSpec(0, testOrientation),
184                    MeasureSpecMatcher.is(0, View.MeasureSpec.UNSPECIFIED));
185        } else {
186            assertThat(behavior2.getSpec(0, testOrientation),
187                    MeasureSpecMatcher.is(parentDim, View.MeasureSpec.AT_MOST));
188        }
189
190        assertThat("it should be measured twice", behavior3.measureSpecs.size(),
191                CoreMatchers.is(2));
192        if (unlimitedSize) {
193            assertThat(behavior3.getSpec(0, testOrientation),
194                    MeasureSpecMatcher.is(0, View.MeasureSpec.UNSPECIFIED));
195        } else {
196            assertThat(behavior3.getSpec(0, testOrientation),
197                    MeasureSpecMatcher.is(parentDim, View.MeasureSpec.AT_MOST));
198        }
199
200        assertThat(behavior3.getSpec(1, testOrientation),
201                MeasureSpecMatcher.is(15, View.MeasureSpec.EXACTLY));
202        final int totalScrollSize = getSize(itemView1, mConfig.mOrientation)
203                + getSize(itemView2, mConfig.mOrientation)
204                + getSize(itemView3, mConfig.mOrientation);
205        assertThat("RecyclerView should wrap its content in the scroll direction",
206                getSize(mRecyclerView, mConfig.mOrientation), CoreMatchers.is(totalScrollSize));
207        assertThat("RecyclerView should wrap its content in the scroll direction",
208                getSize(mRecyclerView, testOrientation), CoreMatchers.is(15));
209    }
210
211    private LinearLayoutManager createFromConfig() {
212        LinearLayoutManager llm = new LinearLayoutManager(getActivity(), mConfig.mOrientation,
213                mConfig.mReverseLayout);
214        llm.setStackFromEnd(mConfig.mStackFromEnd);
215        return llm;
216    }
217}
218