1 /* 2 * Copyright 2018 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 package androidx.percentlayout.widget; 17 18 import static android.support.test.espresso.Espresso.onView; 19 import static android.support.test.espresso.matcher.ViewMatchers.withId; 20 21 import android.os.Build; 22 import android.support.test.filters.SmallTest; 23 import android.view.View; 24 25 import androidx.core.view.ViewCompat; 26 import androidx.percentlayout.test.R; 27 28 import org.junit.Before; 29 import org.junit.Test; 30 31 /** 32 * The arrangement of child views in the layout class in the default LTR (left-to-right) direction 33 * is as follows: 34 * 35 * +---------------------------------------------+ 36 * | | 37 * | TTTTTTTTTTTTTTTTTTTTT | 38 * | | 39 * | S | 40 * | S CCCCCCCCCCCCCCCCCC | 41 * | S CCCCCCCCCCCCCCCCCC | 42 * | S CCCCCCCCCCCCCCCCCC E | 43 * | S CCCCCCCCCCCCCCCCCC E | 44 * | S CCCCCCCCCCCCCCCCCC E | 45 * | CCCCCCCCCCCCCCCCCC E | 46 * | CCCCCCCCCCCCCCCCCC E | 47 * | E | 48 * | | 49 * | BBBBBBBBBBBBBBBBBBBBB | 50 * | | 51 * +---------------------------------------------+ 52 * 53 * The arrangement of child views in the layout class in the RTL (right-to-left) direction 54 * is as follows: 55 * 56 * +---------------------------------------------+ 57 * | | 58 * | TTTTTTTTTTTTTTTTTTTTT | 59 * | | 60 * | S | 61 * | CCCCCCCCCCCCCCCCCC S | 62 * | CCCCCCCCCCCCCCCCCC S | 63 * | E CCCCCCCCCCCCCCCCCC S | 64 * | E CCCCCCCCCCCCCCCCCC S | 65 * | E CCCCCCCCCCCCCCCCCC S | 66 * | E CCCCCCCCCCCCCCCCCC | 67 * | E CCCCCCCCCCCCCCCCCC | 68 * | E | 69 * | | 70 * | BBBBBBBBBBBBBBBBBBBBB | 71 * | | 72 * +---------------------------------------------+ 73 * 74 * Child views are exercising the following percent-based constraints supported by 75 * <code>PercentRelativeLayout</code>: 76 * 77 * <ul> 78 * <li>Top child (marked with T) - width, aspect ratio, top margin, start margin.</li> 79 * <li>Start child (marked with S) - height, aspect ratio, top margin, start margin.</li> 80 * <li>Bottom child (marked with B) - width, aspect ratio, bottom margin, end margin.</li> 81 * <li>Right child (marked with E) - height, aspect ratio, bottom margin, end margin.</li> 82 * <li>Center child (marked with C) - margin (all sides) from the other four children.</li> 83 * </ul> 84 * 85 * Under LTR direction (pre-v17 devices and v17+ with default direction of en-US locale) we are 86 * testing the same assertions as <code>PercentRelativeTest</code>. Under RTL direction (on v17+ 87 * devices with Espresso-powered direction switch) we are testing the reverse assertions along the 88 * X axis for all child views. 89 * 90 * Note that due to a bug in the core {@link RelativeLayout} (base class of 91 * {@link PercentRelativeLayout}) in how it treats end margin of child views on v17 devices, we are 92 * skipping all tests in this class for v17 devices. This is in line with the overall contract 93 * of percent-based layouts provided by the support library - we do not work around / fix bugs in 94 * the core classes, but rather just provide a translation layer between percentage-based values 95 * and pixel-based ones. 96 */ 97 @SmallTest 98 public class PercentRelativeRtlTest extends BaseInstrumentationTestCase<TestRelativeRtlActivity> { 99 private PercentRelativeLayout mPercentRelativeLayout; 100 private int mContainerWidth; 101 private int mContainerHeight; 102 103 public PercentRelativeRtlTest() { 104 super(TestRelativeRtlActivity.class); 105 } 106 107 @Before 108 public void setUp() throws Exception { 109 final TestRelativeRtlActivity activity = mActivityTestRule.getActivity(); 110 mPercentRelativeLayout = (PercentRelativeLayout) activity.findViewById(R.id.container); 111 mContainerWidth = mPercentRelativeLayout.getWidth(); 112 mContainerHeight = mPercentRelativeLayout.getHeight(); 113 } 114 115 private void switchToRtl() { 116 // Force the container to RTL mode 117 onView(withId(R.id.container)).perform( 118 LayoutDirectionActions.setLayoutDirection(ViewCompat.LAYOUT_DIRECTION_RTL)); 119 120 // Force a full measure + layout pass on the container 121 mPercentRelativeLayout.measure( 122 View.MeasureSpec.makeMeasureSpec(mContainerWidth, View.MeasureSpec.EXACTLY), 123 View.MeasureSpec.makeMeasureSpec(mContainerHeight, View.MeasureSpec.EXACTLY)); 124 mPercentRelativeLayout.layout(mPercentRelativeLayout.getLeft(), 125 mPercentRelativeLayout.getTop(), mPercentRelativeLayout.getRight(), 126 mPercentRelativeLayout.getBottom()); 127 } 128 129 @Test 130 public void testTopChild() { 131 if (Build.VERSION.SDK_INT == 17) { 132 return; 133 } 134 final View childToTest = mPercentRelativeLayout.findViewById(R.id.child_top); 135 136 if (Build.VERSION.SDK_INT >= 17) { 137 switchToRtl(); 138 139 final int childRight = childToTest.getRight(); 140 assertFuzzyEquals("Child start margin as 20% of the container", 141 0.2f * mContainerWidth, mContainerWidth - childRight); 142 } else { 143 final int childLeft = childToTest.getLeft(); 144 assertFuzzyEquals("Child start margin as 20% of the container", 145 0.2f * mContainerWidth, childLeft); 146 } 147 148 final int childTop = childToTest.getTop(); 149 assertFuzzyEquals("Child top margin as 5% of the container", 150 0.05f * mContainerHeight, childTop); 151 152 final int childWidth = childToTest.getWidth(); 153 final int childHeight = childToTest.getHeight(); 154 155 assertFuzzyEquals("Child width as 50% of the container", 156 0.5f * mContainerWidth, childWidth); 157 assertFuzzyEquals("Child aspect ratio of 2000%", 158 0.05f * childWidth, childHeight); 159 } 160 161 @Test 162 public void testStartChild() { 163 if (Build.VERSION.SDK_INT == 17) { 164 return; 165 } 166 final View childToTest = mPercentRelativeLayout.findViewById(R.id.child_start); 167 168 if (Build.VERSION.SDK_INT >= 17) { 169 switchToRtl(); 170 171 final int childRight = childToTest.getRight(); 172 assertFuzzyEquals("Child start margin as 5% of the container", 173 0.05f * mContainerWidth, mContainerWidth - childRight); 174 } else { 175 final int childLeft = childToTest.getLeft(); 176 assertFuzzyEquals("Child start margin as 5% of the container", 177 0.05f * mContainerWidth, childLeft); 178 } 179 180 final int childWidth = childToTest.getWidth(); 181 final int childHeight = childToTest.getHeight(); 182 183 assertFuzzyEquals("Child height as 50% of the container", 184 0.5f * mContainerHeight, childHeight); 185 assertFuzzyEquals("Child aspect ratio of 5%", 186 0.05f * childHeight, childWidth); 187 188 final int childTop = childToTest.getTop(); 189 190 assertFuzzyEquals("Child top margin as 20% of the container", 191 0.2f * mContainerHeight, childTop); 192 } 193 194 @Test 195 public void testBottomChild() { 196 if (Build.VERSION.SDK_INT == 17) { 197 return; 198 } 199 final View childToTest = mPercentRelativeLayout.findViewById(R.id.child_bottom); 200 201 if (Build.VERSION.SDK_INT >= 17) { 202 switchToRtl(); 203 204 final int childLeft = childToTest.getLeft(); 205 assertFuzzyEquals("Child end margin as 20% of the container", 206 0.2f * mContainerWidth, childLeft); 207 } else { 208 final int childRight = childToTest.getRight(); 209 assertFuzzyEquals("Child end margin as 20% of the container", 210 0.2f * mContainerWidth, mContainerWidth - childRight); 211 } 212 213 214 final int childWidth = childToTest.getWidth(); 215 final int childHeight = childToTest.getHeight(); 216 217 assertFuzzyEquals("Child width as 40% of the container", 218 0.4f * mContainerWidth, childWidth); 219 assertFuzzyEquals("Child aspect ratio of 2000%", 220 0.05f * childWidth, childHeight); 221 222 final int childBottom = childToTest.getBottom(); 223 224 assertFuzzyEquals("Child bottom margin as 5% of the container", 225 0.05f * mContainerHeight, mContainerHeight - childBottom); 226 } 227 228 @Test 229 public void testEndChild() { 230 if (Build.VERSION.SDK_INT == 17) { 231 return; 232 } 233 final View childToTest = mPercentRelativeLayout.findViewById(R.id.child_end); 234 235 if (Build.VERSION.SDK_INT >= 17) { 236 switchToRtl(); 237 238 final int childLeft = childToTest.getLeft(); 239 assertFuzzyEquals("Child end margin as 5% of the container", 240 0.05f * mContainerWidth, childLeft); 241 } else { 242 final int childRight = childToTest.getRight(); 243 assertFuzzyEquals("Child end margin as 5% of the container", 244 0.05f * mContainerWidth, mContainerWidth - childRight); 245 } 246 247 final int childWidth = childToTest.getWidth(); 248 final int childHeight = childToTest.getHeight(); 249 250 assertFuzzyEquals("Child height as 50% of the container", 251 0.4f * mContainerHeight, childHeight); 252 assertFuzzyEquals("Child aspect ratio of 5%", 253 0.05f * childHeight, childWidth); 254 255 final int childBottom = childToTest.getBottom(); 256 257 assertFuzzyEquals("Child bottom margin as 20% of the container", 258 0.2f * mContainerHeight, mContainerHeight - childBottom); 259 } 260 261 @Test 262 public void testCenterChild() { 263 if (Build.VERSION.SDK_INT == 17) { 264 return; 265 } 266 final View childToTest = mPercentRelativeLayout.findViewById(R.id.child_center); 267 268 boolean supportsRtl = Build.VERSION.SDK_INT >= 17; 269 if (supportsRtl) { 270 switchToRtl(); 271 } 272 273 final int childLeft = childToTest.getLeft(); 274 final int childTop = childToTest.getTop(); 275 final int childRight = childToTest.getRight(); 276 final int childBottom = childToTest.getBottom(); 277 278 final View leftChild = supportsRtl 279 ? mPercentRelativeLayout.findViewById(R.id.child_end) 280 : mPercentRelativeLayout.findViewById(R.id.child_start); 281 assertFuzzyEquals("Child left margin as 10% of the container", 282 leftChild.getRight() + 0.1f * mContainerWidth, childLeft); 283 284 final View topChild = mPercentRelativeLayout.findViewById(R.id.child_top); 285 assertFuzzyEquals("Child top margin as 10% of the container", 286 topChild.getBottom() + 0.1f * mContainerHeight, childTop); 287 288 final View rightChild = supportsRtl 289 ? mPercentRelativeLayout.findViewById(R.id.child_start) 290 : mPercentRelativeLayout.findViewById(R.id.child_end); 291 assertFuzzyEquals("Child right margin as 10% of the container", 292 rightChild.getLeft() - 0.1f * mContainerWidth, childRight); 293 294 final View bottomChild = mPercentRelativeLayout.findViewById(R.id.child_bottom); 295 assertFuzzyEquals("Child bottom margin as 10% of the container", 296 bottomChild.getTop() - 0.1f * mContainerHeight, childBottom); 297 } 298 } 299