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 org.junit.Before; 20import org.junit.Test; 21import org.junit.runner.RunWith; 22import org.junit.runners.Parameterized; 23 24import android.graphics.Color; 25import android.test.suitebuilder.annotation.MediumTest; 26import android.view.View; 27 28import java.util.ArrayList; 29import java.util.List; 30 31import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL; 32import static android.support.v7.widget.LinearLayoutManager.VERTICAL; 33import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 34import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 35import static org.hamcrest.MatcherAssert.assertThat; 36import static android.support.v7.widget.BaseWrapContentTest.WrapContentConfig; 37import static android.support.v7.widget.GridLayoutManagerTest.Config; 38import static org.hamcrest.CoreMatchers.*; 39import static android.view.View.MeasureSpec.UNSPECIFIED; 40import static android.view.View.MeasureSpec.AT_MOST; 41import static android.view.View.MeasureSpec.EXACTLY; 42 43@RunWith(Parameterized.class) 44@MediumTest 45public class GridLayoutManagerWrapContentWithAspectRatioTest 46 extends BaseWrapContentWithAspectRatioTest { 47 48 @Parameterized.Parameters(name = "{0} {1} {2}") 49 public static List<Object[]> params() { 50 List<Object[]> params = new ArrayList<>(); 51 for (int orientation : new int[]{VERTICAL, HORIZONTAL}) { 52 for (boolean reverseLayout : new boolean[]{false, true}) { 53 for (boolean unlimitedW : new boolean[]{true, false}) { 54 for (boolean unlimitedH : new boolean[]{true, false}) { 55 for (int behavior1Size : new int[]{8, 10, 12}) { 56 params.add(new Object[]{ 57 new WrapContentConfig(unlimitedW, unlimitedH), 58 new Config(3, orientation, reverseLayout), 59 behavior1Size 60 }); 61 } 62 63 } 64 } 65 66 } 67 } 68 return params; 69 } 70 71 private GridLayoutManagerTest.Config mConfig; 72 73 private int mBehavior1Size; 74 75 int mTestOrientation; 76 77 boolean mUnlimited; 78 79 RecyclerView.LayoutManager mLayoutManager; 80 81 BaseWrapContentTest.WrappedRecyclerView mRecyclerView; 82 83 OrientationHelper mHelper; 84 85 public GridLayoutManagerWrapContentWithAspectRatioTest(WrapContentConfig wrapContentConfig, 86 GridLayoutManagerTest.Config config, int behavior1Size) { 87 super(wrapContentConfig); 88 mConfig = config; 89 mBehavior1Size = behavior1Size; 90 } 91 92 @Before 93 public final void init() { 94 TestedFrameLayout.FullControlLayoutParams lp = 95 mWrapContentConfig.toLayoutParams(WRAP_CONTENT, WRAP_CONTENT); 96 if (mConfig.mOrientation == VERTICAL) { 97 mTestOrientation = HORIZONTAL; 98 mUnlimited = lp.wSpec != null; 99 } else { 100 mTestOrientation = VERTICAL; 101 mUnlimited = lp.hSpec != null; 102 } 103 mLayoutManager = createFromConfig(); 104 105 mRecyclerView = new BaseWrapContentTest.WrappedRecyclerView(getActivity()); 106 mHelper = OrientationHelper.createOrientationHelper( 107 mLayoutManager, 1 - mConfig.mOrientation); 108 109 mRecyclerView.setBackgroundColor(Color.rgb(0, 0, 255)); 110 mRecyclerView.setLayoutManager(mLayoutManager); 111 mRecyclerView.setLayoutParams(lp); 112 } 113 114 @Test 115 public void testChildWithMultipleSpans() throws Throwable { 116 MeasureBehavior behavior1; 117 behavior1 = new MeasureBehavior(mBehavior1Size, mBehavior1Size, 118 mTestOrientation == HORIZONTAL ? MATCH_PARENT : WRAP_CONTENT, 119 mTestOrientation == VERTICAL ? MATCH_PARENT : WRAP_CONTENT); 120 121 MeasureBehavior behavior2 = new MeasureBehavior( 122 mTestOrientation == HORIZONTAL ? 30 : 10, 123 mTestOrientation == VERTICAL ? 30 : 10, WRAP_CONTENT, WRAP_CONTENT); 124 WrapContentAdapter adapter = new WrapContentAdapter(behavior1, behavior2); 125 ((GridLayoutManager) mLayoutManager).setSpanSizeLookup( 126 new GridLayoutManager.SpanSizeLookup() { 127 @Override 128 public int getSpanSize(int position) { 129 return position == 1 ? 2 : 1; 130 } 131 }); 132 mRecyclerView.setAdapter(adapter); 133 setRecyclerView(mRecyclerView); 134 mRecyclerView.waitUntilLayout(); 135 136 final int parentSize = getSize((View) mRecyclerView.getParent(), mTestOrientation); 137 138 if (mUnlimited) { 139 assertThat(behavior1.getSpec(0, mTestOrientation), 140 MeasureSpecMatcher.mode(UNSPECIFIED)); 141 assertThat(behavior2.getSpec(0, mTestOrientation), 142 MeasureSpecMatcher.mode(UNSPECIFIED)); 143 } else { 144 int[] borders = GridLayoutManager.calculateItemBorders(null, 145 mConfig.mSpanCount, parentSize); 146 assertThat(behavior1.getSpec(0, mTestOrientation), 147 MeasureSpecMatcher.is(borders[1] - borders[0], AT_MOST)); 148 assertThat(behavior2.getSpec(0, mTestOrientation), 149 MeasureSpecMatcher.is(borders[3] - borders[1], AT_MOST)); 150 } 151 // child0 should be measured again because it measured its size as 10 152 assertThat(behavior1.getSpec(1, mTestOrientation), 153 MeasureSpecMatcher.is(15, EXACTLY)); 154 assertThat(behavior1.getSpec(1, mConfig.mOrientation), 155 MeasureSpecMatcher.mode(UNSPECIFIED)); 156 switch (mBehavior1Size) { 157 case 10: 158 assertThat(behavior1.measureSpecs.size(), is(2)); 159 assertThat(behavior2.measureSpecs.size(), is(1)); 160 break; 161 case 8: 162 assertThat(behavior2.measureSpecs.size(), is(1)); 163 assertThat(behavior1.measureSpecs.size(), is(3)); 164 assertThat(behavior1.getSpec(2, mTestOrientation), 165 MeasureSpecMatcher.is(15, EXACTLY)); 166 assertThat(behavior1.getSpec(2, mConfig.mOrientation), 167 MeasureSpecMatcher.is(10, EXACTLY)); 168 break; 169 case 12: 170 assertThat(behavior1.measureSpecs.size(), is(2)); 171 assertThat(behavior2.measureSpecs.size(), is(2)); 172 assertThat(behavior2.getSpec(1, mTestOrientation), 173 MeasureSpecMatcher.is(30, AT_MOST)); 174 assertThat(behavior2.getSpec(1, mConfig.mOrientation), 175 MeasureSpecMatcher.is(12, EXACTLY)); 176 break; 177 } 178 179 View child0 = mRecyclerView.getChildAt(0); 180 assertThat(getSize(child0, mTestOrientation), is(15)); 181 182 View child1 = mRecyclerView.getChildAt(1); 183 assertThat(getSize(child1, mTestOrientation), is(30)); 184 185 assertThat(mHelper.getDecoratedStart(child0), is(0)); 186 assertThat(mHelper.getDecoratedStart(child1), is(15)); 187 188 assertThat(mHelper.getDecoratedEnd(child0), is(15)); 189 assertThat(mHelper.getDecoratedEnd(child1), is(45)); 190 191 assertThat(mHelper.getDecoratedMeasurementInOther(child0), 192 is(Math.max(10, mBehavior1Size))); 193 assertThat(mHelper.getDecoratedMeasurementInOther(child1), 194 is(Math.max(10, mBehavior1Size))); 195 196 assertThat(getSize(mRecyclerView, mTestOrientation), is(45)); 197 assertThat(getSize(mRecyclerView, 1 - mTestOrientation), is(Math.max(10, mBehavior1Size))); 198 } 199 200 @Test 201 public void testChildWithMatchParentInOtherDirection() throws Throwable { 202 MeasureBehavior behavior1; 203 behavior1 = new MeasureBehavior(mBehavior1Size, mBehavior1Size, 204 mTestOrientation == HORIZONTAL ? MATCH_PARENT : WRAP_CONTENT, 205 mTestOrientation == VERTICAL ? MATCH_PARENT : WRAP_CONTENT); 206 207 MeasureBehavior behavior2 = new MeasureBehavior( 208 mTestOrientation == HORIZONTAL ? 15 : 10, 209 mTestOrientation == VERTICAL ? 15 : 10, WRAP_CONTENT, WRAP_CONTENT); 210 WrapContentAdapter adapter = new WrapContentAdapter(behavior1, behavior2); 211 212 mRecyclerView.setAdapter(adapter); 213 setRecyclerView(mRecyclerView); 214 mRecyclerView.waitUntilLayout(); 215 final int parentSize = getSize((View) mRecyclerView.getParent(), mTestOrientation); 216 if (mUnlimited) { 217 assertThat(behavior1.getSpec(0, mTestOrientation), 218 MeasureSpecMatcher.mode(UNSPECIFIED)); 219 assertThat(behavior2.getSpec(0, mTestOrientation), 220 MeasureSpecMatcher.mode(UNSPECIFIED)); 221 } else { 222 int[] borders = GridLayoutManager.calculateItemBorders(null, mConfig.mSpanCount, 223 parentSize); 224 assertThat(behavior1.getSpec(0, mTestOrientation), 225 MeasureSpecMatcher.is(borders[1] - borders[0], AT_MOST)); 226 assertThat(behavior2.getSpec(0, mTestOrientation), 227 MeasureSpecMatcher.is(borders[2] - borders[1], AT_MOST)); 228 } 229 // child0 should be measured again because it measured its size as 10 230 assertThat(behavior1.getSpec(1, mTestOrientation), 231 MeasureSpecMatcher.is(15, EXACTLY)); 232 assertThat(behavior1.getSpec(1, mConfig.mOrientation), 233 MeasureSpecMatcher.mode(UNSPECIFIED)); 234 switch (mBehavior1Size) { 235 case 10: 236 assertThat(behavior1.measureSpecs.size(), is(2)); 237 assertThat(behavior2.measureSpecs.size(), is(1)); 238 break; 239 case 8: 240 assertThat(behavior2.measureSpecs.size(), is(1)); 241 assertThat(behavior1.measureSpecs.size(), is(3)); 242 assertThat(behavior1.getSpec(2, mTestOrientation), 243 MeasureSpecMatcher.is(15, EXACTLY)); 244 assertThat(behavior1.getSpec(2, mConfig.mOrientation), 245 MeasureSpecMatcher.is(10, EXACTLY)); 246 break; 247 case 12: 248 assertThat(behavior1.measureSpecs.size(), is(2)); 249 assertThat(behavior2.measureSpecs.size(), is(2)); 250 assertThat(behavior2.getSpec(1, mTestOrientation), 251 MeasureSpecMatcher.is(15, AT_MOST)); 252 assertThat(behavior2.getSpec(1, mConfig.mOrientation), 253 MeasureSpecMatcher.is(12, EXACTLY)); 254 break; 255 } 256 257 View child0 = mRecyclerView.getChildAt(0); 258 assertThat(getSize(child0, mTestOrientation), is(15)); 259 260 View child1 = mRecyclerView.getChildAt(1); 261 assertThat(getSize(child1, mTestOrientation), is(15)); 262 263 assertThat(mHelper.getDecoratedStart(child0), is(0)); 264 assertThat(mHelper.getDecoratedStart(child1), is(15)); 265 266 assertThat(mHelper.getDecoratedEnd(child0), is(15)); 267 assertThat(mHelper.getDecoratedEnd(child1), is(30)); 268 269 assertThat(mHelper.getDecoratedMeasurementInOther(child0), 270 is(Math.max(10, mBehavior1Size))); 271 assertThat(mHelper.getDecoratedMeasurementInOther(child1), 272 is(Math.max(10, mBehavior1Size))); 273 274 assertThat(getSize(mRecyclerView, mTestOrientation), is(45)); 275 assertThat(getSize(mRecyclerView, 1 - mTestOrientation), is(Math.max(10, mBehavior1Size))); 276 } 277 278 @Test 279 public void testAllChildrenWrapContentInOtherDirection() throws Throwable { 280 MeasureBehavior behavior1; 281 behavior1 = new MeasureBehavior(mBehavior1Size, mBehavior1Size, WRAP_CONTENT, WRAP_CONTENT); 282 283 MeasureBehavior behavior2 = new MeasureBehavior( 284 mTestOrientation == HORIZONTAL ? 15 : 10, 285 mTestOrientation == VERTICAL ? 15 : 10, WRAP_CONTENT, WRAP_CONTENT); 286 WrapContentAdapter adapter = new WrapContentAdapter(behavior1, behavior2); 287 288 mRecyclerView.setAdapter(adapter); 289 setRecyclerView(mRecyclerView); 290 mRecyclerView.waitUntilLayout(); 291 final int parentSize = getSize((View) mRecyclerView.getParent(), mTestOrientation); 292 if (mUnlimited) { 293 assertThat(behavior1.getSpec(0, mTestOrientation), 294 MeasureSpecMatcher.mode(UNSPECIFIED)); 295 assertThat(behavior2.getSpec(0, mTestOrientation), 296 MeasureSpecMatcher.mode(UNSPECIFIED)); 297 } else { 298 int[] borders = GridLayoutManager.calculateItemBorders(null, 299 mConfig.mSpanCount, parentSize); 300 assertThat(behavior1.getSpec(0, mTestOrientation), 301 MeasureSpecMatcher.is(borders[1] - borders[0], AT_MOST)); 302 assertThat(behavior2.getSpec(0, mTestOrientation), 303 MeasureSpecMatcher.is(borders[2] - borders[1], AT_MOST)); 304 } 305 306 switch (mBehavior1Size) { 307 case 10: 308 assertThat(behavior1.measureSpecs.size(), is(1)); 309 assertThat(behavior2.measureSpecs.size(), is(1)); 310 break; 311 case 8: 312 assertThat(behavior2.measureSpecs.size(), is(1)); 313 assertThat(behavior1.measureSpecs.size(), is(2)); 314 assertThat(behavior1.getSpec(1, mTestOrientation), 315 MeasureSpecMatcher.is(15, AT_MOST)); 316 assertThat(behavior1.getSpec(1, mConfig.mOrientation), 317 MeasureSpecMatcher.is(10, EXACTLY)); 318 break; 319 case 12: 320 assertThat(behavior1.measureSpecs.size(), is(1)); 321 assertThat(behavior2.measureSpecs.size(), is(2)); 322 assertThat(behavior2.getSpec(1, mTestOrientation), 323 MeasureSpecMatcher.is(15, AT_MOST)); 324 assertThat(behavior2.getSpec(1, mConfig.mOrientation), 325 MeasureSpecMatcher.is(12, EXACTLY)); 326 break; 327 } 328 329 View child0 = mRecyclerView.getChildAt(0); 330 assertThat(getSize(child0, mTestOrientation), is(mBehavior1Size)); 331 332 View child1 = mRecyclerView.getChildAt(1); 333 assertThat(getSize(child1, mTestOrientation), is(15)); 334 335 assertThat(mHelper.getDecoratedStart(child0), is(0)); 336 assertThat(mHelper.getDecoratedStart(child1), is(15)); 337 338 assertThat(mHelper.getDecoratedEnd(child0), is(mBehavior1Size)); 339 assertThat(mHelper.getDecoratedEnd(child1), is(30)); 340 341 assertThat(mHelper.getDecoratedMeasurementInOther(child0), 342 is(Math.max(10, mBehavior1Size))); 343 assertThat(mHelper.getDecoratedMeasurementInOther(child1), 344 is(Math.max(10, mBehavior1Size))); 345 346 assertThat(getSize(mRecyclerView, mTestOrientation), is(45)); 347 assertThat(getSize(mRecyclerView, 1 - mTestOrientation), is(Math.max(10, mBehavior1Size))); 348 } 349 350 private RecyclerView.LayoutManager createFromConfig() { 351 return new GridLayoutManager(getActivity(), mConfig.mSpanCount, 352 mConfig.mOrientation, mConfig.mReverseLayout); 353 } 354} 355