1package org.robolectric.shadows; 2 3import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; 4import static android.os.Build.VERSION_CODES.LOLLIPOP; 5import static org.assertj.core.api.Assertions.assertThat; 6import static org.junit.Assert.assertEquals; 7import static org.junit.Assert.assertFalse; 8import static org.junit.Assert.assertNotNull; 9import static org.junit.Assert.assertNotSame; 10import static org.junit.Assert.assertTrue; 11import static org.mockito.Mockito.mock; 12import static org.mockito.Mockito.verify; 13import static org.mockito.Mockito.verifyZeroInteractions; 14import static org.robolectric.Robolectric.buildActivity; 15import static org.robolectric.Shadows.shadowOf; 16 17import android.app.Activity; 18import android.content.Context; 19import android.graphics.BitmapFactory; 20import android.graphics.Point; 21import android.graphics.Rect; 22import android.graphics.drawable.BitmapDrawable; 23import android.graphics.drawable.ColorDrawable; 24import android.graphics.drawable.Drawable; 25import android.os.Bundle; 26import android.util.AttributeSet; 27import android.view.ContextMenu; 28import android.view.HapticFeedbackConstants; 29import android.view.MotionEvent; 30import android.view.View; 31import android.view.View.MeasureSpec; 32import android.view.View.OnClickListener; 33import android.view.View.OnLongClickListener; 34import android.view.ViewGroup; 35import android.view.ViewParent; 36import android.view.ViewTreeObserver; 37import android.view.WindowId; 38import android.view.WindowManager; 39import android.view.animation.AlphaAnimation; 40import android.view.animation.Animation; 41import android.widget.FrameLayout; 42import android.widget.LinearLayout; 43import java.util.ArrayList; 44import java.util.List; 45import java.util.concurrent.atomic.AtomicBoolean; 46import org.junit.Before; 47import org.junit.Test; 48import org.junit.runner.RunWith; 49import org.robolectric.R; 50import org.robolectric.Robolectric; 51import org.robolectric.RobolectricTestRunner; 52import org.robolectric.RuntimeEnvironment; 53import org.robolectric.android.DeviceConfig; 54import org.robolectric.android.controller.ActivityController; 55import org.robolectric.annotation.AccessibilityChecks; 56import org.robolectric.annotation.Config; 57import org.robolectric.util.ReflectionHelpers; 58import org.robolectric.util.TestRunnable; 59 60@RunWith(RobolectricTestRunner.class) 61public class ShadowViewTest { 62 private View view; 63 private List<String> transcript; 64 65 @Before 66 public void setUp() throws Exception { 67 transcript = new ArrayList<>(); 68 view = new View(RuntimeEnvironment.application); 69 } 70 71 @Test 72 public void testHasNullLayoutParamsUntilAddedToParent() throws Exception { 73 assertThat(view.getLayoutParams()).isNull(); 74 new LinearLayout(RuntimeEnvironment.application).addView(view); 75 assertThat(view.getLayoutParams()).isNotNull(); 76 } 77 78 @Test 79 public void layout_shouldAffectWidthAndHeight() throws Exception { 80 assertThat(view.getWidth()).isEqualTo(0); 81 assertThat(view.getHeight()).isEqualTo(0); 82 83 view.layout(100, 200, 303, 404); 84 assertThat(view.getWidth()).isEqualTo(303 - 100); 85 assertThat(view.getHeight()).isEqualTo(404 - 200); 86 } 87 88 @Test 89 public void measuredDimensions() throws Exception { 90 View view1 = new View(RuntimeEnvironment.application) { 91 { 92 setMeasuredDimension(123, 456); 93 } 94 }; 95 assertThat(view1.getMeasuredWidth()).isEqualTo(123); 96 assertThat(view1.getMeasuredHeight()).isEqualTo(456); 97 } 98 99 @Test 100 public void layout_shouldCallOnLayoutOnlyIfChanged() throws Exception { 101 View view1 = new View(RuntimeEnvironment.application) { 102 @Override 103 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 104 transcript.add("onLayout " + changed + " " + left + " " + top + " " + right + " " + bottom); 105 } 106 }; 107 view1.layout(0, 0, 0, 0); 108 assertThat(transcript).isEmpty(); 109 view1.layout(1, 2, 3, 4); 110 assertThat(transcript).containsExactly("onLayout true 1 2 3 4"); 111 transcript.clear(); 112 view1.layout(1, 2, 3, 4); 113 assertThat(transcript).isEmpty(); 114 } 115 116 @Test 117 public void shouldFocus() throws Exception { 118 final List<String> transcript = new ArrayList<>(); 119 120 view.setOnFocusChangeListener(new View.OnFocusChangeListener() { 121 @Override 122 public void onFocusChange(View v, boolean hasFocus) { 123 transcript.add(hasFocus ? "Gained focus" : "Lost focus"); 124 } 125 }); 126 127 assertFalse(view.isFocused()); 128 assertFalse(view.hasFocus()); 129 assertThat(transcript).isEmpty(); 130 131 view.requestFocus(); 132 assertFalse(view.isFocused()); 133 assertFalse(view.hasFocus()); 134 assertThat(transcript).isEmpty(); 135 136 view.setFocusable(true); 137 view.requestFocus(); 138 assertTrue(view.isFocused()); 139 assertTrue(view.hasFocus()); 140 assertThat(transcript).containsExactly("Gained focus"); 141 transcript.clear(); 142 143 shadowOf(view).setMyParent(new LinearLayout(RuntimeEnvironment.application)); // we can never lose focus unless a parent can take it 144 145 view.clearFocus(); 146 assertFalse(view.isFocused()); 147 assertFalse(view.hasFocus()); 148 assertThat(transcript).containsExactly("Lost focus"); 149 } 150 151 @Test 152 public void shouldNotBeFocusableByDefault() throws Exception { 153 assertFalse(view.isFocusable()); 154 155 view.setFocusable(true); 156 assertTrue(view.isFocusable()); 157 } 158 159 @Test 160 public void shouldKnowIfThisOrAncestorsAreVisible() throws Exception { 161 assertThat(view.isShown()).describedAs("view isn't considered shown unless it has a view root").isFalse(); 162 shadowOf(view).setMyParent(ReflectionHelpers.createNullProxy(ViewParent.class)); 163 assertThat(view.isShown()).isTrue(); 164 shadowOf(view).setMyParent(null); 165 166 ViewGroup parent = new LinearLayout(RuntimeEnvironment.application); 167 parent.addView(view); 168 169 ViewGroup grandParent = new LinearLayout(RuntimeEnvironment.application); 170 grandParent.addView(parent); 171 172 grandParent.setVisibility(View.GONE); 173 174 assertFalse(view.isShown()); 175 } 176 177 @Test 178 public void shouldInflateMergeRootedLayoutAndNotCreateReferentialLoops() throws Exception { 179 LinearLayout root = new LinearLayout(RuntimeEnvironment.application); 180 LinearLayout.inflate(RuntimeEnvironment.application, R.layout.inner_merge, root); 181 for (int i = 0; i < root.getChildCount(); i++) { 182 View child = root.getChildAt(i); 183 assertNotSame(root, child); 184 } 185 } 186 187 @Test 188 public void performLongClick_shouldClickOnView() throws Exception { 189 OnLongClickListener clickListener = mock(OnLongClickListener.class); 190 shadowOf(view).setMyParent(ReflectionHelpers.createNullProxy(ViewParent.class)); 191 view.setOnLongClickListener(clickListener); 192 view.performLongClick(); 193 194 verify(clickListener).onLongClick(view); 195 } 196 197 @Test 198 public void checkedClick_shouldClickOnView() throws Exception { 199 OnClickListener clickListener = mock(OnClickListener.class); 200 shadowOf(view).setMyParent(ReflectionHelpers.createNullProxy(ViewParent.class)); 201 view.setOnClickListener(clickListener); 202 shadowOf(view).checkedPerformClick(); 203 204 verify(clickListener).onClick(view); 205 } 206 207 @Test(expected = RuntimeException.class) 208 public void checkedClick_shouldThrowIfViewIsNotVisible() throws Exception { 209 ViewGroup grandParent = new LinearLayout(RuntimeEnvironment.application); 210 ViewGroup parent = new LinearLayout(RuntimeEnvironment.application); 211 grandParent.addView(parent); 212 parent.addView(view); 213 grandParent.setVisibility(View.GONE); 214 215 shadowOf(view).checkedPerformClick(); 216 } 217 218 @Test(expected = RuntimeException.class) 219 public void checkedClick_shouldThrowIfViewIsDisabled() throws Exception { 220 view.setEnabled(false); 221 shadowOf(view).checkedPerformClick(); 222 } 223 224 /* 225 * This test will throw an exception because the accessibility checks depend on the Android 226 * Support Library. If the support library is included at some point, a single test from 227 * AccessibilityUtilTest could be moved here to make sure the accessibility checking is run. 228 */ 229 @Test(expected = RuntimeException.class) 230 @AccessibilityChecks 231 public void checkedClick_withA11yChecksAnnotation_shouldThrow() throws Exception { 232 shadowOf(view).checkedPerformClick(); 233 } 234 235 @Test 236 public void getBackground_shouldReturnNullIfNoBackgroundHasBeenSet() throws Exception { 237 assertThat(view.getBackground()).isNull(); 238 } 239 240 @Test 241 public void shouldSetBackgroundColor() { 242 int red = 0xffff0000; 243 view.setBackgroundColor(red); 244 assertThat((ColorDrawable) view.getBackground()).isEqualTo(new ColorDrawable(red)); 245 } 246 247 @Test 248 public void shouldSetBackgroundResource() throws Exception { 249 view.setBackgroundResource(R.drawable.an_image); 250 assertThat(view.getBackground()).isEqualTo(view.getResources().getDrawable(R.drawable.an_image)); 251 assertThat(shadowOf(view).getBackgroundResourceId()).isEqualTo(R.drawable.an_image); 252 } 253 254 @Test 255 public void shouldClearBackgroundResource() throws Exception { 256 view.setBackgroundResource(R.drawable.an_image); 257 view.setBackgroundResource(0); 258 assertThat(view.getBackground()).isEqualTo(null); 259 assertThat(shadowOf(view).getBackgroundResourceId()).isEqualTo(-1); 260 } 261 262 @Test 263 public void shouldRecordBackgroundColor() { 264 int[] colors = {R.color.black, R.color.clear, R.color.white}; 265 266 for (int color : colors) { 267 view.setBackgroundColor(color); 268 assertThat(shadowOf(view).getBackgroundColor()).isEqualTo(color); 269 } 270 } 271 272 @Test 273 public void shouldRecordBackgroundDrawable() { 274 Drawable drawable = new BitmapDrawable(BitmapFactory.decodeFile("some/fake/file")); 275 view.setBackgroundDrawable(drawable); 276 assertThat(view.getBackground()).isSameAs(drawable); 277 assertThat(ShadowView.visualize(view)).isEqualTo("background:\nBitmap for file:some/fake/file"); 278 } 279 280 @Test 281 public void shouldPostActionsToTheMessageQueue() throws Exception { 282 ShadowLooper.pauseMainLooper(); 283 284 TestRunnable runnable = new TestRunnable(); 285 view.post(runnable); 286 assertFalse(runnable.wasRun); 287 288 ShadowLooper.unPauseMainLooper(); 289 assertTrue(runnable.wasRun); 290 } 291 292 @Test 293 public void shouldPostInvalidateDelayed() throws Exception { 294 ShadowLooper.pauseMainLooper(); 295 296 view.postInvalidateDelayed(100); 297 ShadowView shadowView = shadowOf(view); 298 assertFalse(shadowView.wasInvalidated()); 299 300 ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); 301 assertTrue(shadowView.wasInvalidated()); 302 } 303 304 @Test 305 public void shouldPostActionsToTheMessageQueueWithDelay() throws Exception { 306 ShadowLooper.pauseMainLooper(); 307 308 TestRunnable runnable = new TestRunnable(); 309 view.postDelayed(runnable, 1); 310 assertFalse(runnable.wasRun); 311 312 Robolectric.getForegroundThreadScheduler().advanceBy(1); 313 assertTrue(runnable.wasRun); 314 } 315 316 @Test 317 public void shouldRemovePostedCallbacksFromMessageQueue() throws Exception { 318 TestRunnable runnable = new TestRunnable(); 319 view.postDelayed(runnable, 1); 320 321 view.removeCallbacks(runnable); 322 323 Robolectric.getForegroundThreadScheduler().advanceBy(1); 324 assertThat(runnable.wasRun).isFalse(); 325 } 326 327 @Test 328 public void shouldSupportAllConstructors() throws Exception { 329 new View(RuntimeEnvironment.application); 330 new View(RuntimeEnvironment.application, null); 331 new View(RuntimeEnvironment.application, null, 0); 332 } 333 334 @Test 335 public void shouldRememberIsPressed() { 336 view.setPressed(true); 337 assertTrue(view.isPressed()); 338 view.setPressed(false); 339 assertFalse(view.isPressed()); 340 } 341 342 @Test 343 public void shouldAddOnClickListenerFromAttribute() throws Exception { 344 AttributeSet attrs = Robolectric.buildAttributeSet() 345 .addAttribute(android.R.attr.onClick, "clickMe") 346 .build() 347 ; 348 349 view = new View(RuntimeEnvironment.application, attrs); 350 assertNotNull(shadowOf(view).getOnClickListener()); 351 } 352 353 @Test 354 public void shouldCallOnClickWithAttribute() throws Exception { 355 MyActivity myActivity = buildActivity(MyActivity.class).create().get(); 356 357 AttributeSet attrs = Robolectric.buildAttributeSet() 358 .addAttribute(android.R.attr.onClick, "clickMe") 359 .build(); 360 361 view = new View(myActivity, attrs); 362 view.performClick(); 363 assertTrue("Should have been called", myActivity.called); 364 } 365 366 @Test(expected = RuntimeException.class) 367 public void shouldThrowExceptionWithBadMethodName() throws Exception { 368 MyActivity myActivity = buildActivity(MyActivity.class).create().get(); 369 370 AttributeSet attrs = Robolectric.buildAttributeSet() 371 .addAttribute(android.R.attr.onClick, "clickYou") 372 .build(); 373 374 view = new View(myActivity, attrs); 375 view.performClick(); 376 } 377 378 @Test 379 public void shouldSetAnimation() throws Exception { 380 Animation anim = new TestAnimation(); 381 view.setAnimation(anim); 382 assertThat(view.getAnimation()).isSameAs(anim); 383 } 384 385 @Test 386 public void shouldFindViewWithTag() { 387 view.setTag("tagged"); 388 assertThat((View) view.findViewWithTag("tagged")).isSameAs(view); 389 } 390 391 @Test 392 public void scrollTo_shouldStoreTheScrolledCoordinates() throws Exception { 393 view.scrollTo(1, 2); 394 assertThat(shadowOf(view).scrollToCoordinates).isEqualTo(new Point(1, 2)); 395 } 396 397 @Test 398 public void shouldScrollTo() throws Exception { 399 view.scrollTo(7, 6); 400 401 assertEquals(7, view.getScrollX()); 402 assertEquals(6, view.getScrollY()); 403 } 404 405 @Test 406 public void shouldGetScrollXAndY() { 407 assertEquals(0, view.getScrollX()); 408 assertEquals(0, view.getScrollY()); 409 } 410 411 @Test 412 public void getViewTreeObserver_shouldReturnTheSameObserverFromMultipleCalls() throws Exception { 413 ViewTreeObserver observer = view.getViewTreeObserver(); 414 assertThat(observer).isInstanceOf(ViewTreeObserver.class); 415 assertThat(view.getViewTreeObserver()).isSameAs(observer); 416 } 417 418 @Test 419 public void dispatchTouchEvent_sendsMotionEventToOnTouchEvent() throws Exception { 420 TouchableView touchableView = new TouchableView(RuntimeEnvironment.application); 421 MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 12f, 34f, 0); 422 touchableView.dispatchTouchEvent(event); 423 assertThat(touchableView.event).isSameAs(event); 424 view.dispatchTouchEvent(event); 425 assertThat(shadowOf(view).getLastTouchEvent()).isSameAs(event); 426 } 427 428 @Test 429 public void dispatchTouchEvent_listensToFalseFromListener() throws Exception { 430 final AtomicBoolean called = new AtomicBoolean(false); 431 view.setOnTouchListener(new View.OnTouchListener() { 432 @Override 433 public boolean onTouch(View view, MotionEvent motionEvent) { 434 called.set(true); return false; 435 } 436 }); 437 MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 12f, 34f, 0); 438 view.dispatchTouchEvent(event); 439 assertThat(shadowOf(view).getLastTouchEvent()).isSameAs(event); 440 assertThat(called.get()).isTrue(); 441 } 442 443 @Test 444 public void test_nextFocusDownId() throws Exception { 445 assertEquals(View.NO_ID, view.getNextFocusDownId()); 446 447 view.setNextFocusDownId(R.id.icon); 448 assertEquals(R.id.icon, view.getNextFocusDownId()); 449 } 450 451 @Test 452 public void startAnimation() { 453 TestView view = new TestView(buildActivity(Activity.class).create().get()); 454 AlphaAnimation animation = new AlphaAnimation(0, 1); 455 456 Animation.AnimationListener listener = mock(Animation.AnimationListener.class); 457 animation.setAnimationListener(listener); 458 view.startAnimation(animation); 459 460 verify(listener).onAnimationStart(animation); 461 verify(listener).onAnimationEnd(animation); 462 } 463 464 @Test 465 public void setAnimation() { 466 TestView view = new TestView(buildActivity(Activity.class).create().get()); 467 AlphaAnimation animation = new AlphaAnimation(0, 1); 468 469 Animation.AnimationListener listener = mock(Animation.AnimationListener.class); 470 animation.setAnimationListener(listener); 471 animation.setStartTime(1000); 472 view.setAnimation(animation); 473 474 verifyZeroInteractions(listener); 475 476 Robolectric.getForegroundThreadScheduler().advanceToNextPostedRunnable(); 477 478 verify(listener).onAnimationStart(animation); 479 verify(listener).onAnimationEnd(animation); 480 } 481 482 @Test 483 public void setNullAnimation() { 484 TestView view = new TestView(buildActivity(Activity.class).create().get()); 485 view.setAnimation(null); 486 assertThat(view.getAnimation()).isNull(); 487 } 488 489 @Test 490 public void test_measuredDimension() { 491 // View does not provide its own onMeasure implementation 492 TestView view1 = new TestView(buildActivity(Activity.class).create().get()); 493 494 assertThat(view1.getHeight()).isEqualTo(0); 495 assertThat(view1.getWidth()).isEqualTo(0); 496 assertThat(view1.getMeasuredHeight()).isEqualTo(0); 497 assertThat(view1.getMeasuredWidth()).isEqualTo(0); 498 499 view1.measure(MeasureSpec.makeMeasureSpec(150, MeasureSpec.AT_MOST), 500 MeasureSpec.makeMeasureSpec(300, MeasureSpec.AT_MOST)); 501 502 assertThat(view1.getHeight()).isEqualTo(0); 503 assertThat(view1.getWidth()).isEqualTo(0); 504 assertThat(view1.getMeasuredHeight()).isEqualTo(300); 505 assertThat(view1.getMeasuredWidth()).isEqualTo(150); 506 } 507 508 @Test 509 public void test_measuredDimensionCustomView() { 510 // View provides its own onMeasure implementation 511 TestView2 view2 = new TestView2(buildActivity(Activity.class).create().get(), 300, 100); 512 513 assertThat(view2.getWidth()).isEqualTo(0); 514 assertThat(view2.getHeight()).isEqualTo(0); 515 assertThat(view2.getMeasuredWidth()).isEqualTo(0); 516 assertThat(view2.getMeasuredHeight()).isEqualTo(0); 517 518 view2.measure(MeasureSpec.makeMeasureSpec(200, MeasureSpec.AT_MOST), 519 MeasureSpec.makeMeasureSpec(50, MeasureSpec.AT_MOST)); 520 521 assertThat(view2.getWidth()).isEqualTo(0); 522 assertThat(view2.getHeight()).isEqualTo(0); 523 assertThat(view2.getMeasuredWidth()).isEqualTo(300); 524 assertThat(view2.getMeasuredHeight()).isEqualTo(100); 525 } 526 527 @Test 528 public void shouldGetAndSetTranslations() throws Exception { 529 view = new TestView(buildActivity(Activity.class).create().get()); 530 view.setTranslationX(8.9f); 531 view.setTranslationY(4.6f); 532 533 assertThat(view.getTranslationX()).isEqualTo(8.9f); 534 assertThat(view.getTranslationY()).isEqualTo(4.6f); 535 } 536 537 @Test 538 public void shouldGetAndSetAlpha() throws Exception { 539 view = new TestView(buildActivity(Activity.class).create().get()); 540 view.setAlpha(9.1f); 541 542 assertThat(view.getAlpha()).isEqualTo(9.1f); 543 } 544 545 @Test 546 public void itKnowsIfTheViewIsShown() { 547 shadowOf(view).setMyParent(ReflectionHelpers.createNullProxy(ViewParent.class)); // a view is only considered visible if it is added to a view root 548 view.setVisibility(View.VISIBLE); 549 assertThat(view.isShown()).isTrue(); 550 } 551 552 @Test 553 public void itKnowsIfTheViewIsNotShown() { 554 view.setVisibility(View.GONE); 555 assertThat(view.isShown()).isFalse(); 556 557 view.setVisibility(View.INVISIBLE); 558 assertThat(view.isShown()).isFalse(); 559 } 560 561 @Test 562 public void shouldTrackRequestLayoutCalls() throws Exception { 563 assertThat(shadowOf(view).didRequestLayout()).isFalse(); 564 view.requestLayout(); 565 assertThat(shadowOf(view).didRequestLayout()).isTrue(); 566 shadowOf(view).setDidRequestLayout(false); 567 assertThat(shadowOf(view).didRequestLayout()).isFalse(); 568 } 569 570 @Test 571 public void shouldClickAndNotClick() throws Exception { 572 assertThat(view.isClickable()).isFalse(); 573 view.setClickable(true); 574 assertThat(view.isClickable()).isTrue(); 575 view.setClickable(false); 576 assertThat(view.isClickable()).isFalse(); 577 view.setOnClickListener(new OnClickListener() { 578 @Override 579 public void onClick(View v) { 580 ; 581 } 582 }); 583 assertThat(view.isClickable()).isTrue(); 584 } 585 586 @Test 587 public void shouldLongClickAndNotLongClick() throws Exception { 588 assertThat(view.isLongClickable()).isFalse(); 589 view.setLongClickable(true); 590 assertThat(view.isLongClickable()).isTrue(); 591 view.setLongClickable(false); 592 assertThat(view.isLongClickable()).isFalse(); 593 view.setOnLongClickListener(new OnLongClickListener() { 594 @Override 595 public boolean onLongClick(View v) { 596 return false; 597 } 598 }); 599 assertThat(view.isLongClickable()).isTrue(); 600 } 601 602 @Test 603 public void rotationX() { 604 view.setRotationX(10f); 605 assertThat(view.getRotationX()).isEqualTo(10f); 606 } 607 608 @Test 609 public void rotationY() { 610 view.setRotationY(20f); 611 assertThat(view.getRotationY()).isEqualTo(20f); 612 } 613 614 @Test 615 public void rotation() { 616 view.setRotation(30f); 617 assertThat(view.getRotation()).isEqualTo(30f); 618 } 619 620 @Test 621 @Config(minSdk = LOLLIPOP) 622 public void cameraDistance() { 623 view.setCameraDistance(100f); 624 assertThat(view.getCameraDistance()).isEqualTo(100f); 625 } 626 627 @Test 628 public void scaleX() { 629 assertThat(view.getScaleX()).isEqualTo(1f); 630 view.setScaleX(0.5f); 631 assertThat(view.getScaleX()).isEqualTo(0.5f); 632 } 633 634 @Test 635 public void scaleY() { 636 assertThat(view.getScaleY()).isEqualTo(1f); 637 view.setScaleY(0.5f); 638 assertThat(view.getScaleY()).isEqualTo(0.5f); 639 } 640 641 @Test 642 public void pivotX() { 643 view.setPivotX(10f); 644 assertThat(view.getPivotX()).isEqualTo(10f); 645 } 646 647 @Test 648 public void pivotY() { 649 view.setPivotY(10f); 650 assertThat(view.getPivotY()).isEqualTo(10f); 651 } 652 653 @Test 654 @Config(minSdk = LOLLIPOP) 655 public void elevation() { 656 view.setElevation(10f); 657 assertThat(view.getElevation()).isEqualTo(10f); 658 } 659 660 @Test 661 public void translationX() { 662 view.setTranslationX(10f); 663 assertThat(view.getTranslationX()).isEqualTo(10f); 664 } 665 666 @Test 667 public void translationY() { 668 view.setTranslationY(10f); 669 assertThat(view.getTranslationY()).isEqualTo(10f); 670 } 671 672 @Test 673 @Config(minSdk = LOLLIPOP) 674 public void translationZ() { 675 view.setTranslationZ(10f); 676 assertThat(view.getTranslationZ()).isEqualTo(10f); 677 } 678 679 @Test 680 @Config(minSdk = LOLLIPOP) 681 public void clipToOutline() { 682 view.setClipToOutline(true); 683 assertThat(view.getClipToOutline()).isTrue(); 684 } 685 686 @Test 687 public void performHapticFeedback_shouldSetLastPerformedHapticFeedback() throws Exception { 688 assertThat(shadowOf(view).lastHapticFeedbackPerformed()).isEqualTo(-1); 689 view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 690 assertThat(shadowOf(view).lastHapticFeedbackPerformed()).isEqualTo(HapticFeedbackConstants.LONG_PRESS); 691 } 692 693 @Test 694 public void canAssertThatSuperDotOnLayoutWasCalledFromViewSubclasses() throws Exception { 695 TestView2 view = new TestView2(buildActivity(Activity.class).create().get(), 1111, 1112); 696 assertThat(shadowOf(view).onLayoutWasCalled()).isFalse(); 697 view.onLayout(true, 1, 2, 3, 4); 698 assertThat(shadowOf(view).onLayoutWasCalled()).isTrue(); 699 } 700 701 @Test 702 public void setScrolls_canBeAskedFor() throws Exception { 703 view.setScrollX(234); 704 view.setScrollY(544); 705 assertThat(view.getScrollX()).isEqualTo(234); 706 assertThat(view.getScrollY()).isEqualTo(544); 707 } 708 709 @Test 710 public void setScrolls_firesOnScrollChanged() throws Exception { 711 TestView testView = new TestView(buildActivity(Activity.class).create().get()); 712 testView.setScrollX(122); 713 testView.setScrollY(150); 714 testView.setScrollX(453); 715 assertThat(testView.oldl).isEqualTo(122); 716 testView.setScrollY(54); 717 assertThat(testView.l).isEqualTo(453); 718 assertThat(testView.t).isEqualTo(54); 719 assertThat(testView.oldt).isEqualTo(150); 720 } 721 722 private static class TestAnimation extends Animation { 723 } 724 725 private static class TouchableView extends View { 726 MotionEvent event; 727 728 public TouchableView(Context context) { 729 super(context); 730 } 731 732 @Override 733 public boolean onTouchEvent(MotionEvent event) { 734 this.event = event; 735 return false; 736 } 737 } 738 739 public static class TestView extends View { 740 boolean onAnimationEndWasCalled; 741 private int l; 742 private int t; 743 private int oldl; 744 private int oldt; 745 746 public TestView(Context context) { 747 super(context); 748 } 749 750 @Override 751 protected void onAnimationEnd() { 752 super.onAnimationEnd(); 753 onAnimationEndWasCalled = true; 754 } 755 756 @Override 757 public void onScrollChanged(int l, int t, int oldl, int oldt) { 758 this.l = l; 759 this.t = t; 760 this.oldl = oldl; 761 this.oldt = oldt; 762 } 763 } 764 765 private static class TestView2 extends View { 766 767 private int minWidth; 768 private int minHeight; 769 770 public TestView2(Context context, int minWidth, int minHeight) { 771 super(context); 772 this.minWidth = minWidth; 773 this.minHeight = minHeight; 774 } 775 776 @Override 777 public void onLayout(boolean changed, int l, int t, int r, int b) { 778 super.onLayout(changed, l, t, r, b); 779 } 780 781 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 782 setMeasuredDimension(minWidth, minHeight); 783 } 784 } 785 786 @Test 787 public void shouldCallOnAttachedToAndDetachedFromWindow() throws Exception { 788 MyView parent = new MyView("parent", transcript); 789 parent.addView(new MyView("child", transcript)); 790 assertThat(transcript).isEmpty(); 791 792 Activity activity = Robolectric.buildActivity(ContentViewActivity.class).create().get(); 793 activity.getWindowManager().addView(parent, new WindowManager.LayoutParams(100, 100)); 794 assertThat(transcript).containsExactly("parent attached", "child attached"); 795 transcript.clear(); 796 797 parent.addView(new MyView("another child", transcript)); 798 assertThat(transcript).containsExactly("another child attached"); 799 transcript.clear(); 800 801 MyView temporaryChild = new MyView("temporary child", transcript); 802 parent.addView(temporaryChild); 803 assertThat(transcript).containsExactly("temporary child attached"); 804 transcript.clear(); 805 assertTrue(shadowOf(temporaryChild).isAttachedToWindow()); 806 807 parent.removeView(temporaryChild); 808 assertThat(transcript).containsExactly("temporary child detached"); 809 assertFalse(shadowOf(temporaryChild).isAttachedToWindow()); 810 } 811 812 @Test @Config(minSdk = JELLY_BEAN_MR2) 813 public void getWindowId_shouldReturnValidObjectWhenAttached() throws Exception { 814 MyView parent = new MyView("parent", transcript); 815 MyView child = new MyView("child", transcript); 816 parent.addView(child); 817 818 assertThat(parent.getWindowId()).isNull(); 819 assertThat(child.getWindowId()).isNull(); 820 821 Activity activity = Robolectric.buildActivity(ContentViewActivity.class).create().get(); 822 activity.getWindowManager().addView(parent, new WindowManager.LayoutParams(100, 100)); 823 824 WindowId windowId = parent.getWindowId(); 825 assertThat(windowId).isNotNull(); 826 assertThat(child.getWindowId()).isSameAs(windowId); 827 assertThat(child.getWindowId()).isEqualTo(windowId); // equals must work! 828 829 MyView anotherChild = new MyView("another child", transcript); 830 parent.addView(anotherChild); 831 assertThat(anotherChild.getWindowId()).isEqualTo(windowId); 832 833 parent.removeView(anotherChild); 834 assertThat(anotherChild.getWindowId()).isNull(); 835 } 836 837 // todo looks like this is flaky... 838 @Test 839 public void removeAllViews_shouldCallOnAttachedToAndDetachedFromWindow() throws Exception { 840 MyView parent = new MyView("parent", transcript); 841 Activity activity = Robolectric.buildActivity(ContentViewActivity.class).create().get(); 842 activity.getWindowManager().addView(parent, new WindowManager.LayoutParams(100, 100)); 843 844 parent.addView(new MyView("child", transcript)); 845 parent.addView(new MyView("another child", transcript)); 846 ShadowLooper.runUiThreadTasks(); 847 transcript.clear(); 848 parent.removeAllViews(); 849 ShadowLooper.runUiThreadTasks(); 850 assertThat(transcript).containsExactly("another child detached", "child detached"); 851 } 852 853 @Test 854 public void capturesOnSystemUiVisibilityChangeListener() throws Exception { 855 TestView testView = new TestView(buildActivity(Activity.class).create().get()); 856 View.OnSystemUiVisibilityChangeListener changeListener = new View.OnSystemUiVisibilityChangeListener() { 857 @Override 858 public void onSystemUiVisibilityChange(int i) { } 859 }; 860 testView.setOnSystemUiVisibilityChangeListener(changeListener); 861 862 assertThat(changeListener).isEqualTo(shadowOf(testView).getOnSystemUiVisibilityChangeListener()); 863 } 864 865 @Test 866 public void capturesOnCreateContextMenuListener() throws Exception { 867 TestView testView = new TestView(buildActivity(Activity.class).create().get()); 868 assertThat(shadowOf(testView).getOnCreateContextMenuListener()).isNull(); 869 870 View.OnCreateContextMenuListener createListener = new View.OnCreateContextMenuListener() { 871 @Override 872 public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {} 873 }; 874 875 testView.setOnCreateContextMenuListener(createListener); 876 assertThat(shadowOf(testView).getOnCreateContextMenuListener()).isEqualTo(createListener); 877 878 testView.setOnCreateContextMenuListener(null); 879 assertThat(shadowOf(testView).getOnCreateContextMenuListener()).isNull(); 880 } 881 882 @Test 883 public void setsGlobalVisibleRect() { 884 Rect globalVisibleRect = new Rect(); 885 shadowOf(view).setGlobalVisibleRect(new Rect()); 886 assertThat(view.getGlobalVisibleRect(globalVisibleRect)) 887 .isFalse(); 888 assertThat(globalVisibleRect.isEmpty()) 889 .isTrue(); 890 assertThat(view.getGlobalVisibleRect(globalVisibleRect, new Point(1, 1))) 891 .isFalse(); 892 assertThat(globalVisibleRect.isEmpty()) 893 .isTrue(); 894 895 shadowOf(view).setGlobalVisibleRect(new Rect(1, 2, 3, 4)); 896 assertThat(view.getGlobalVisibleRect(globalVisibleRect)) 897 .isTrue(); 898 assertThat(globalVisibleRect) 899 .isEqualTo(new Rect(1, 2, 3, 4)); 900 assertThat(view.getGlobalVisibleRect(globalVisibleRect, new Point(1, 1))) 901 .isTrue(); 902 assertThat(globalVisibleRect) 903 .isEqualTo(new Rect(0, 1, 2, 3)); 904 } 905 906 @Test 907 public void usesDefaultGlobalVisibleRect() { 908 final ActivityController<Activity> activityController = Robolectric.buildActivity(Activity.class); 909 final Activity activity = activityController.get(); 910 activity.setContentView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 911 ViewGroup.LayoutParams.MATCH_PARENT)); 912 activityController.setup(); 913 914 Rect globalVisibleRect = new Rect(); 915 assertThat(view.getGlobalVisibleRect(globalVisibleRect)) 916 .isTrue(); 917 assertThat(globalVisibleRect) 918 .isEqualTo(new Rect(0, 25, 919 DeviceConfig.DEFAULT_SCREEN_SIZE.width, DeviceConfig.DEFAULT_SCREEN_SIZE.height)); 920 } 921 922 public static class MyActivity extends Activity { 923 public boolean called; 924 925 @SuppressWarnings("UnusedDeclaration") 926 public void clickMe(View view) { 927 called = true; 928 } 929 } 930 931 public static class MyView extends LinearLayout { 932 private String name; 933 private List<String> transcript; 934 935 public MyView(String name, List<String> transcript) { 936 super(RuntimeEnvironment.application); 937 this.name = name; 938 this.transcript = transcript; 939 } 940 941 @Override protected void onAttachedToWindow() { 942 transcript.add(name + " attached"); 943 super.onAttachedToWindow(); 944 } 945 946 @Override protected void onDetachedFromWindow() { 947 transcript.add(name + " detached"); 948 super.onDetachedFromWindow(); 949 } 950 } 951 952 private static class ContentViewActivity extends Activity { 953 @Override 954 protected void onCreate(Bundle savedInstanceState) { 955 super.onCreate(savedInstanceState); 956 setContentView(new FrameLayout(this)); 957 } 958 } 959} 960