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