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