Home | History | Annotate | Download | only in shadows
      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