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.wear.widget; 18 19import static android.support.test.espresso.Espresso.onView; 20import static android.support.test.espresso.matcher.ViewMatchers.withId; 21import static android.support.wear.widget.util.MoreViewAssertions.approximateBottom; 22import static android.support.wear.widget.util.MoreViewAssertions.approximateTop; 23import static android.support.wear.widget.util.MoreViewAssertions.bottom; 24import static android.support.wear.widget.util.MoreViewAssertions.left; 25import static android.support.wear.widget.util.MoreViewAssertions.right; 26import static android.support.wear.widget.util.MoreViewAssertions.screenBottom; 27import static android.support.wear.widget.util.MoreViewAssertions.screenLeft; 28import static android.support.wear.widget.util.MoreViewAssertions.screenRight; 29import static android.support.wear.widget.util.MoreViewAssertions.screenTop; 30import static android.support.wear.widget.util.MoreViewAssertions.top; 31 32import static org.hamcrest.Matchers.closeTo; 33import static org.hamcrest.Matchers.equalTo; 34import static org.hamcrest.Matchers.is; 35 36import android.content.Intent; 37import android.support.test.InstrumentationRegistry; 38import android.support.test.filters.MediumTest; 39import android.support.test.rule.ActivityTestRule; 40import android.support.test.runner.AndroidJUnit4; 41import android.support.wear.test.R; 42import android.support.wear.widget.util.WakeLockRule; 43import android.util.DisplayMetrics; 44import android.view.View; 45 46import org.junit.Rule; 47import org.junit.Test; 48import org.junit.runner.RunWith; 49 50import java.util.HashMap; 51import java.util.Map; 52 53@MediumTest 54@RunWith(AndroidJUnit4.class) 55public class BoxInsetLayoutTest { 56 private static final float FACTOR = 0.146467f; //(1 - sqrt(2)/2)/2 57 58 @Rule 59 public final WakeLockRule mWakeLock = new WakeLockRule(); 60 61 @Rule 62 public final ActivityTestRule<LayoutTestActivity> mActivityRule = new ActivityTestRule<>( 63 LayoutTestActivity.class, true, false); 64 65 @Test 66 public void testCase1() throws Throwable { 67 mActivityRule.launchActivity(new Intent().putExtra(LayoutTestActivity 68 .EXTRA_LAYOUT_RESOURCE_ID, R.layout.box_inset_layout_testcase_1)); 69 DisplayMetrics dm = InstrumentationRegistry.getTargetContext().getResources() 70 .getDisplayMetrics(); 71 int boxInset = (int) (FACTOR * Math.min(dm.widthPixels, dm.heightPixels)); 72 73 int desiredPadding = 0; 74 if (mActivityRule.getActivity().getResources().getConfiguration().isScreenRound()) { 75 desiredPadding = boxInset; 76 } 77 78 ViewFetchingRunnable customRunnable = new ViewFetchingRunnable(){ 79 @Override 80 public void run() { 81 View box = mActivityRule.getActivity().findViewById(R.id.box); 82 mIdViewMap.put(R.id.box, box); 83 } 84 }; 85 mActivityRule.runOnUiThread(customRunnable); 86 87 View box = customRunnable.mIdViewMap.get(R.id.box); 88 // proxy for window location 89 View boxParent = (View) box.getParent(); 90 int parentLeft = boxParent.getLeft(); 91 int parentTop = boxParent.getTop(); 92 int parentRight = boxParent.getLeft() + boxParent.getWidth(); 93 int parentBottom = boxParent.getTop() + boxParent.getHeight(); 94 95 // Child 1 is match_parent width and height 96 // layout_box=right|bottom 97 // Padding of boxInset should be added to the right and bottom sides only 98 onView(withId(R.id.child1)) 99 .check(screenLeft(equalTo(parentLeft))) 100 .check(screenTop(equalTo(parentTop))) 101 .check(screenRight(equalTo(parentRight - desiredPadding))) 102 .check(screenBottom(equalTo(parentBottom - desiredPadding))); 103 104 // Content 1 is is width and height match_parent 105 // The bottom and right sides should be inset by boxInset pixels due to padding 106 // on the parent view 107 onView(withId(R.id.content1)) 108 .check(screenLeft(equalTo(parentLeft))) 109 .check(screenTop(equalTo(parentTop))) 110 .check(screenRight(equalTo(parentRight - desiredPadding))) 111 .check(screenBottom(equalTo(parentBottom - desiredPadding))); 112 } 113 114 @Test 115 public void testCase2() throws Throwable { 116 mActivityRule.launchActivity( 117 new Intent().putExtra(LayoutTestActivity.EXTRA_LAYOUT_RESOURCE_ID, 118 R.layout.box_inset_layout_testcase_2)); 119 DisplayMetrics dm = 120 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics(); 121 int boxInset = (int) (FACTOR * Math.min(dm.widthPixels, dm.heightPixels)); 122 123 int desiredPadding = 0; 124 if (mActivityRule.getActivity().getResources().getConfiguration().isScreenRound()) { 125 desiredPadding = boxInset; 126 } 127 128 ViewFetchingRunnable customRunnable = new ViewFetchingRunnable(){ 129 @Override 130 public void run() { 131 View box = mActivityRule.getActivity().findViewById(R.id.box); 132 View child1 = mActivityRule.getActivity().findViewById(R.id.child1); 133 View child2 = mActivityRule.getActivity().findViewById(R.id.child2); 134 View child3 = mActivityRule.getActivity().findViewById(R.id.child3); 135 View child4 = mActivityRule.getActivity().findViewById(R.id.child4); 136 mIdViewMap.put(R.id.box, box); 137 mIdViewMap.put(R.id.child1, child1); 138 mIdViewMap.put(R.id.child2, child2); 139 mIdViewMap.put(R.id.child3, child3); 140 mIdViewMap.put(R.id.child4, child4); 141 142 } 143 }; 144 mActivityRule.runOnUiThread(customRunnable); 145 146 View box = customRunnable.mIdViewMap.get(R.id.box); 147 View child1 = customRunnable.mIdViewMap.get(R.id.child1); 148 View child2 = customRunnable.mIdViewMap.get(R.id.child2); 149 View child3 = customRunnable.mIdViewMap.get(R.id.child3); 150 View child4 = customRunnable.mIdViewMap.get(R.id.child4); 151 152 // proxy for window location 153 View boxParent = (View) box.getParent(); 154 int parentLeft = boxParent.getLeft(); 155 int parentTop = boxParent.getTop(); 156 int parentRight = boxParent.getLeft() + boxParent.getWidth(); 157 int parentBottom = boxParent.getTop() + boxParent.getHeight(); 158 int parentWidth = boxParent.getWidth(); 159 int parentHeight = boxParent.getHeight(); 160 161 // Child 1 is width match_parent, height=60dp, gravity top 162 // layout_box=all means it should have padding added to left, top and right 163 onView(withId(R.id.child1)) 164 .check(screenLeft(is(equalTo(parentLeft + desiredPadding)))) 165 .check(screenTop(is(equalTo(parentTop + desiredPadding)))) 166 .check(screenRight(is(equalTo(parentRight - desiredPadding)))) 167 .check(screenBottom(is(equalTo(parentTop + desiredPadding + child1.getHeight())))); 168 169 // Content 1 is width and height match_parent 170 // the left top and right edges should be inset by boxInset pixels, due to 171 // padding in the parent 172 onView(withId(R.id.content1)) 173 .check(screenLeft(equalTo(parentLeft + desiredPadding))) 174 .check(screenTop(equalTo(parentTop + desiredPadding))) 175 .check(screenRight(equalTo(parentRight - desiredPadding))); 176 177 // Child 2 is width match_parent, height=60dp, gravity bottom 178 // layout_box=all means it should have padding added to left, bottom and right 179 onView(withId(R.id.child2)) 180 .check(screenLeft(is(equalTo(parentLeft + desiredPadding)))) 181 .check(screenTop(is(equalTo(parentBottom - desiredPadding - child2.getHeight())))) 182 .check(screenRight(is(equalTo(parentRight - desiredPadding)))) 183 .check(screenBottom(is(equalTo(parentBottom - desiredPadding)))); 184 185 // Content 2 is width and height match_parent 186 // the left bottom and right edges should be inset by boxInset pixels, due to 187 // padding in the parent 188 onView(withId(R.id.content2)) 189 .check(screenLeft(equalTo(parentLeft + desiredPadding))) 190 .check(screenRight(equalTo(parentRight - desiredPadding))) 191 .check(screenBottom(equalTo(parentBottom - desiredPadding))); 192 193 // Child 3 is width wrap_content, height=20dp, gravity left|center_vertical. 194 // layout_box=all means it should have padding added to left 195 // marginLeft be ignored due to gravity and layout_box=all (screenLeft=0) 196 onView(withId(R.id.child3)) 197 .check(screenLeft(is(equalTo(parentLeft + desiredPadding)))) 198 .check(approximateTop(is(closeTo((parentHeight / 2 - child3.getHeight() / 2), 1)))) 199 .check(screenRight(is(equalTo(parentLeft + desiredPadding + child3.getWidth())))) 200 .check(approximateBottom(is( 201 closeTo((parentHeight / 2 + child3.getHeight() / 2), 1)))); 202 203 // Content 3 width and height match_parent 204 // the left edge should be offset from the screen edge by boxInset pixels, due to left on 205 // the parent 206 onView(withId(R.id.content3)).check(screenLeft(equalTo(desiredPadding))); 207 208 // Child 4 is width wrap_content, height=20dp, gravity right|center_vertical. 209 // layout_box=all means it should have padding added to right 210 // it should have marginRight ignored due to gravity and layout_box=all (screenRight=max) 211 onView(withId(R.id.child4)) 212 .check(screenLeft(is(parentWidth - desiredPadding - child4.getWidth()))) 213 .check(approximateTop(is(closeTo((parentHeight / 2 - child3.getHeight() / 2), 1)))) 214 .check(screenRight(is(equalTo(parentWidth - desiredPadding)))) 215 .check(approximateBottom(is( 216 closeTo((parentHeight / 2 + child4.getHeight() / 2), 1)))); 217 218 // Content 4 width and height wrap_content 219 // the right edge should be offset from the screen edge by boxInset pixels, due to 220 // right on the parent 221 onView(withId(R.id.content4)).check(screenRight(equalTo(parentWidth - desiredPadding))); 222 } 223 224 @Test 225 public void testCase3() throws Throwable { 226 mActivityRule.launchActivity( 227 new Intent().putExtra(LayoutTestActivity.EXTRA_LAYOUT_RESOURCE_ID, 228 R.layout.box_inset_layout_testcase_3)); 229 DisplayMetrics dm = 230 InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics(); 231 int boxInset = (int) (FACTOR * Math.min(dm.widthPixels, dm.heightPixels)); 232 233 int desiredPadding = 0; 234 if (mActivityRule.getActivity().getResources().getConfiguration().isScreenRound()) { 235 desiredPadding = boxInset; 236 } 237 238 ViewFetchingRunnable customRunnable = new ViewFetchingRunnable(){ 239 @Override 240 public void run() { 241 View box = mActivityRule.getActivity().findViewById(R.id.box); 242 View child1 = mActivityRule.getActivity().findViewById(R.id.child1); 243 View child2 = mActivityRule.getActivity().findViewById(R.id.child2); 244 View child3 = mActivityRule.getActivity().findViewById(R.id.child3); 245 View child4 = mActivityRule.getActivity().findViewById(R.id.child4); 246 mIdViewMap.put(R.id.box, box); 247 mIdViewMap.put(R.id.child1, child1); 248 mIdViewMap.put(R.id.child2, child2); 249 mIdViewMap.put(R.id.child3, child3); 250 mIdViewMap.put(R.id.child4, child4); 251 } 252 }; 253 mActivityRule.runOnUiThread(customRunnable); 254 255 View box = customRunnable.mIdViewMap.get(R.id.box); 256 View child1 = customRunnable.mIdViewMap.get(R.id.child1); 257 View child2 = customRunnable.mIdViewMap.get(R.id.child2); 258 View child3 = customRunnable.mIdViewMap.get(R.id.child3); 259 View child4 = customRunnable.mIdViewMap.get(R.id.child4); 260 // proxy for window location 261 View boxParent = (View) box.getParent(); 262 int parentLeft = boxParent.getLeft(); 263 int parentTop = boxParent.getTop(); 264 int parentBottom = boxParent.getTop() + boxParent.getHeight(); 265 int parentWidth = boxParent.getWidth(); 266 267 // Child 1 is width and height wrap_content 268 // gravity is top|left, position should be 0,0 on screen 269 onView(withId(R.id.child1)) 270 .check(screenLeft(is(equalTo(parentLeft + desiredPadding)))) 271 .check(screenTop(is(equalTo(parentTop + desiredPadding)))) 272 .check(screenRight(is(equalTo(parentLeft + desiredPadding + child1.getWidth())))) 273 .check(screenBottom(is(equalTo(parentTop + desiredPadding + child1.getHeight())))); 274 275 // Content 1 is width and height wrap_content 276 // the left and top edges should be offset from the screen edges by boxInset pixels 277 onView(withId(R.id.content1)) 278 .check(screenLeft(equalTo(parentLeft + desiredPadding))) 279 .check(screenTop(equalTo(parentTop + desiredPadding))); 280 281 // Child 2 is width and height wrap_content 282 // gravity is top|right, position should be 0,max on screen 283 onView(withId(R.id.child2)) 284 .check(screenLeft(is(equalTo(parentWidth - desiredPadding - child2.getWidth())))) 285 .check(screenTop(is(equalTo(parentTop + desiredPadding)))) 286 .check(screenRight(is(equalTo(parentWidth - desiredPadding)))) 287 .check(screenBottom(is(equalTo(parentTop + desiredPadding + child2.getHeight())))); 288 289 // Content 2 is width and height wrap_content 290 // the top and right edges should be offset from the screen edges by boxInset pixels 291 onView(withId(R.id.content2)) 292 .check(screenTop(equalTo(parentTop + desiredPadding))) 293 .check(screenRight(equalTo(parentWidth - desiredPadding))); 294 295 // Child 3 is width and height wrap_content 296 // gravity is bottom|right, position should be max,max on screen 297 onView(withId(R.id.child3)) 298 .check(screenLeft(is(equalTo(parentWidth - desiredPadding - child3.getWidth())))) 299 .check(screenTop(is( 300 equalTo(parentBottom - desiredPadding - child3.getHeight())))) 301 .check(screenRight(is(equalTo(parentWidth - desiredPadding)))) 302 .check(screenBottom(is(equalTo(parentBottom - desiredPadding)))); 303 304 // Content 3 is width and height wrap_content 305 // the right and bottom edges should be offset from the screen edges by boxInset pixels 306 onView(withId(R.id.content3)) 307 .check(screenBottom(equalTo(parentBottom - desiredPadding))) 308 .check(screenRight(equalTo(parentWidth - desiredPadding))); 309 310 // Child 4 is width and height wrap_content 311 // gravity is bottom|left, position should be max,0 on screen 312 onView(withId(R.id.child4)) 313 .check(screenLeft(is(equalTo(parentLeft + desiredPadding)))) 314 .check(screenTop(is(equalTo(parentBottom - desiredPadding - child4.getHeight())))) 315 .check(screenRight(is(equalTo(parentLeft + desiredPadding + child4.getWidth())))) 316 .check(screenBottom(is(equalTo(parentBottom - desiredPadding)))); 317 318 // Content 3 is width and height wrap_content 319 // the bottom and left edges should be offset from the screen edges by boxInset pixels 320 onView(withId(R.id.content4)).check( 321 screenBottom(equalTo(parentBottom - desiredPadding))) 322 .check(screenLeft(equalTo(parentLeft + desiredPadding))); 323 } 324 325 @Test 326 public void testCase4() throws Throwable { 327 mActivityRule.launchActivity(new Intent().putExtra(LayoutTestActivity 328 .EXTRA_LAYOUT_RESOURCE_ID, R.layout.box_inset_layout_testcase_4)); 329 DisplayMetrics dm = InstrumentationRegistry.getTargetContext().getResources() 330 .getDisplayMetrics(); 331 int boxInset = (int) (FACTOR * Math.min(dm.widthPixels, dm.heightPixels)); 332 333 int desiredPadding = 0; 334 if (mActivityRule.getActivity().getResources().getConfiguration().isScreenRound()) { 335 desiredPadding = boxInset; 336 } 337 338 ViewFetchingRunnable customRunnable = new ViewFetchingRunnable(){ 339 @Override 340 public void run() { 341 View container = mActivityRule.getActivity().findViewById(R.id.container); 342 View child1 = mActivityRule.getActivity().findViewById(R.id.child1); 343 mIdViewMap.put(R.id.container, container); 344 mIdViewMap.put(R.id.child1, child1); 345 346 } 347 }; 348 mActivityRule.runOnUiThread(customRunnable); 349 350 View container = customRunnable.mIdViewMap.get(R.id.container); 351 View child1 = customRunnable.mIdViewMap.get(R.id.child1); 352 // Child 1 is match_parent width and wrap_content height 353 // layout_box=right|left 354 // Padding of boxInset should be added to the right and bottom sides only 355 onView(withId(R.id.child1)).check(left(equalTo(desiredPadding))).check( 356 top(equalTo(container.getTop()))).check( 357 right(equalTo(dm.widthPixels - desiredPadding))).check( 358 bottom(equalTo(container.getTop() + child1.getHeight()))); 359 } 360 361 private abstract class ViewFetchingRunnable implements Runnable { 362 Map<Integer, View> mIdViewMap = new HashMap<>(); 363 } 364} 365